diff --git a/.github/workflows/update-nightly.yml b/.github/workflows/update-nightly.yml
deleted file mode 100644
index 0265ffbebe2ec0..00000000000000
--- a/.github/workflows/update-nightly.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ============================================================================
-
-on:
- workflow_dispatch: # Allow manual triggers
- schedule:
- - cron: 0 4 * * * # 4am UTC is 9pm PDT and 8pm PST
-name: Set nightly branch to master HEAD
-jobs:
- master-to-nightly:
- if: github.repository == 'tensorflow/tensorflow' # Don't do this in forks
- runs-on: ubuntu-latest
- steps:
- - uses: zofrex/mirror-branch@v1
- name: Set nightly branch to master HEAD
- with:
- target-branch: 'nightly'
diff --git a/.zenodo.json b/.zenodo.json
new file mode 100644
index 00000000000000..7161180c51ae3e
--- /dev/null
+++ b/.zenodo.json
@@ -0,0 +1,13 @@
+{
+ "description": "TensorFlow is an end-to-end open source platform for machine learning. It has a comprehensive, flexible ecosystem of tools, libraries, and community resources that lets researchers push the state-of-the-art in ML and developers easily build and deploy ML-powered applications.",
+ "license": "Apache-2.0",
+ "title": "TensorFlow",
+ "upload_type": "software",
+ "creators": [
+ {
+ "name": "TensorFlow Developers"
+ }
+ ],
+ "access_right": "open",
+ "notes": "Specific TensorFlow versions can be found in the \"Versions\" list on the right side of this page.
See the full list of authors on GitHub."
+}
diff --git a/RELEASE.md b/RELEASE.md
index 57759c9bc55951..7b4186050d415e 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -1,24 +1,173 @@
-# Release 2.5.0
-
-
-
-## Breaking Changes
-
-*
-* The `TF_CPP_MIN_VLOG_LEVEL` environment variable has been renamed to to
- `TF_CPP_MAX_VLOG_LEVEL` which correctly describes its effect.
-
-## Known Caveats
+# Release 2.5.3
+
+This releases introduces several vulnerability fixes:
+
+* Fixes a floating point division by 0 when executing convolution operators ([CVE-2022-21725](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21725))
+* Fixes a heap OOB read in shape inference for `ReverseSequence` ([CVE-2022-21728](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21728))
+* Fixes a heap OOB access in `Dequantize` ([CVE-2022-21726](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21726))
+* Fixes an integer overflow in shape inference for `Dequantize` ([CVE-2022-21727](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21727))
+* Fixes a heap OOB access in `FractionalAvgPoolGrad` ([CVE-2022-21730](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21730))
+* Fixes an overflow and divide by zero in `UnravelIndex` ([CVE-2022-21729](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21729))
+* Fixes a type confusion in shape inference for `ConcatV2` ([CVE-2022-21731](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21731))
+* Fixes an OOM in `ThreadPoolHandle` ([CVE-2022-21732](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21732))
+* Fixes an OOM due to integer overflow in `StringNGrams` ([CVE-2022-21733](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21733))
+* Fixes more issues caused by incomplete validation in boosted trees code ([CVE-2021-41208](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41208))
+* Fixes an integer overflows in most sparse component-wise ops ([CVE-2022-23567](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23567))
+* Fixes an integer overflows in `AddManySparseToTensorsMap` ([CVE-2022-23568](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23568))
+* Fixes a number of `CHECK`-failures in `MapStage` ([CVE-2022-21734](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21734))
+* Fixes a division by zero in `FractionalMaxPool` ([CVE-2022-21735](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21735))
+* Fixes a number of `CHECK`-fails when building invalid/overflowing tensor shapes ([CVE-2022-23569](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23569))
+* Fixes an undefined behavior in `SparseTensorSliceDataset` ([CVE-2022-21736](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21736))
+* Fixes an assertion failure based denial of service via faulty bin count operations ([CVE-2022-21737](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21737))
+* Fixes a reference binding to null pointer in `QuantizedMaxPool` ([CVE-2022-21739](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21739))
+* Fixes an integer overflow leading to crash in `SparseCountSparseOutput` ([CVE-2022-21738](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21738))
+* Fixes a heap overflow in `SparseCountSparseOutput` ([CVE-2022-21740](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21740))
+* Fixes an FPE in `BiasAndClamp` in TFLite ([CVE-2022-23557](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23557))
+* Fixes an FPE in depthwise convolutions in TFLite ([CVE-2022-21741](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21741))
+* Fixes an integer overflow in TFLite array creation ([CVE-2022-23558](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23558))
+* Fixes an integer overflow in TFLite ([CVE-2022-23559](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23559))
+* Fixes a dangerous OOB write in TFLite ([CVE-2022-23561](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23561))
+* Fixes a vulnerability leading to read and write outside of bounds in TFLite ([CVE-2022-23560](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23560))
+* Fixes a set of vulnerabilities caused by using insecure temporary files ([CVE-2022-23563](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23563))
+* Fixes an integer overflow in Range resulting in undefined behavior and OOM ([CVE-2022-23562](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23562))
+* Fixes a vulnerability where missing validation causes `tf.sparse.split` to crash when `axis` is a tuple ([CVE-2021-41206](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41206))
+* Fixes a `CHECK`-fail when decoding resource handles from proto ([CVE-2022-23564](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23564))
+* Fixes a `CHECK`-fail with repeated `AttrDef` ([CVE-2022-23565](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23565))
+* Fixes a heap OOB write in Grappler ([CVE-2022-23566](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23566))
+* Fixes a `CHECK`-fail when decoding invalid tensors from proto ([CVE-2022-23571](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23571))
+* Fixes an unitialized variable access in `AssignOp` ([CVE-2022-23573](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23573))
+* Fixes an integer overflow in `OpLevelCostEstimator::CalculateTensorSize` ([CVE-2022-23575](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23575))
+* Fixes an integer overflow in `OpLevelCostEstimator::CalculateOutputSize` ([CVE-2022-23576](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23576))
+* Fixes a null dereference in `GetInitOp` ([CVE-2022-23577](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23577))
+* Fixes a memory leak when a graph node is invalid ([CVE-2022-23578](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23578))
+* Fixes an abort caused by allocating a vector that is too large ([CVE-2022-23580](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23580))
+* Fixes multiple `CHECK`-failures during Grappler's `IsSimplifiableReshape` ([CVE-2022-23581](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23581))
+* Fixes multiple `CHECK`-failures during Grappler's `SafeToRemoveIdentity` ([CVE-2022-23579](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23579))
+* Fixes multiple `CHECK`-failures in `TensorByteSize` ([CVE-2022-23582](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23582))
+* Fixes multiple `CHECK`-failures in binary ops due to type confusion ([CVE-2022-23583](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23583))
+* Fixes a use after free in `DecodePng` kernel ([CVE-2022-23584](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23584))
+* Fixes a memory leak in decoding PNG images ([CVE-2022-23585](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23585))
+* Fixes multiple `CHECK`-fails in `function.cc` ([CVE-2022-23586](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23586))
+* Fixes multiple `CHECK`-fails due to attempting to build a reference tensor ([CVE-2022-23588](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23588))
+* Fixes an integer overflow in Grappler cost estimation of crop and resize operation ([CVE-2022-23587](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23587))
+* Fixes a null pointer dereference in Grappler's `IsConstant` ([CVE-2022-23589](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23589))
+* Fixes a `CHECK` failure in constant folding ([CVE-2021-41197](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41197))
+* Fixes a stack overflow due to self-recursive function in `GraphDef` ([CVE-2022-23591](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23591))
+* Updates `icu` to `69.1` to handle [CVE-2020-10531](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-10531)
+
+# Release 2.5.2
+
+This release introduces several vulnerability fixes:
+
+* Fixes a code injection issue in `saved_model_cli` ([CVE-2021-41228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41228))
+* Fixes a vulnerability due to use of uninitialized value in Tensorflow ([CVE-2021-41225](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41225))
+* Fixes a heap OOB in `FusedBatchNorm` kernels ([CVE-2021-41223](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41223))
+* Fixes an arbitrary memory read in `ImmutableConst` ([CVE-2021-41227](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41227))
+* Fixes a heap OOB in `SparseBinCount` ([CVE-2021-41226](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41226))
+* Fixes a heap OOB in `SparseFillEmptyRows` ([CVE-2021-41224](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41224))
+* Fixes a segfault due to negative splits in `SplitV` ([CVE-2021-41222](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41222))
+* Fixes segfaults and vulnerabilities caused by accesses to invalid memory during shape inference in `Cudnn*` ops ([CVE-2021-41221](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41221))
+* Fixes a null pointer exception when `Exit` node is not preceded by `Enter` op ([CVE-2021-41217](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41217))
+* Fixes an integer division by 0 in `tf.raw_ops.AllToAll` ([CVE-2021-41218](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41218))
+* Fixes an undefined behavior via `nullptr` reference binding in sparse matrix multiplication ([CVE-2021-41219](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41219))
+* Fixes a heap buffer overflow in `Transpose` ([CVE-2021-41216](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41216))
+* Prevents deadlocks arising from mutually recursive `tf.function` objects ([CVE-2021-41213](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41213))
+* Fixes a null pointer exception in `DeserializeSparse` ([CVE-2021-41215](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41215))
+* Fixes an undefined behavior arising from reference binding to `nullptr` in `tf.ragged.cross` ([CVE-2021-41214](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41214))
+* Fixes a heap OOB read in `tf.ragged.cross` ([CVE-2021-41212](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41212))
+* Fixes a heap OOB read in all `tf.raw_ops.QuantizeAndDequantizeV*` ops ([CVE-2021-41205](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41205))
+* Fixes an FPE in `ParallelConcat` ([CVE-2021-41207](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41207))
+* Fixes FPE issues in convolutions with zero size filters ([CVE-2021-41209](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41209))
+* Fixes a heap OOB read in `tf.raw_ops.SparseCountSparseOutput` ([CVE-2021-41210](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41210))
+* Fixes vulnerabilities caused by incomplete validation in boosted trees code ([CVE-2021-41208](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41208))
+* Fixes vulnerabilities caused by incomplete validation of shapes in multiple TF ops ([CVE-2021-41206](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41206))
+* Fixes a segfault produced while copying constant resource tensor ([CVE-2021-41204](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41204))
+* Fixes a vulnerability caused by unitialized access in `EinsumHelper::ParseEquation` ([CVE-2021-41201](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41201))
+* Fixes several vulnerabilities and segfaults caused by missing validation during checkpoint loading ([CVE-2021-41203](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41203))
+* Fixes an overflow producing a crash in `tf.range` ([CVE-2021-41202](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41202))
+* Fixes an overflow producing a crash in `tf.image.resize` when size is large ([CVE-2021-41199](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41199))
+* Fixes an overflow producing a crash in `tf.tile` when tiling tensor is large ([CVE-2021-41198](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41198))
+* Fixes a vulnerability produced due to incomplete validation in `tf.summary.create_file_writer` ([CVE-2021-41200](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41200))
+* Fixes multiple crashes due to overflow and `CHECK`-fail in ops with large tensor shapes ([CVE-2021-41197](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41197))
+* Fixes a crash in `max_pool3d` when size argument is 0 or negative ([CVE-2021-41196](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41196))
+* Fixes a crash in `tf.math.segment_*` operations ([CVE-2021-41195](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41195))
+* Updates `curl` to `7.78.0` to handle
+ [CVE-2021-22922](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22922),
+ [CVE-2021-22923](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22923),
+ [CVE-2021-22924](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22924),
+ [CVE-2021-22925](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22925),
+ and
+ [CVE-2021-22926](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22926).
+
+# Release 2.5.1
+
+This release introduces several vulnerability fixes:
+
+* Fixes a heap out of bounds access in sparse reduction operations ([CVE-2021-37635](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37635))
+* Fixes a floating point exception in `SparseDenseCwiseDiv` ([CVE-2021-37636](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37636))
+* Fixes a null pointer dereference in `CompressElement` ([CVE-2021-37637](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37637))
+* Fixes a null pointer dereference in `RaggedTensorToTensor` ([CVE-2021-37638](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37638))
+* Fixes a null pointer dereference and a heap OOB read arising from operations restoring tensors ([CVE-2021-37639](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37639))
+* Fixes an integer division by 0 in sparse reshaping ([CVE-2021-37640](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37640))
+* Fixes a division by 0 in `ResourceScatterDiv` ([CVE-2021-37642](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37642))
+* Fixes a heap OOB in `RaggedGather` ([CVE-2021-37641](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37641))
+* Fixes a `std::abort` raised from `TensorListReserve` ([CVE-2021-37644](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37644))
+* Fixes a null pointer dereference in `MatrixDiagPartOp` ([CVE-2021-37643](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37643))
+* Fixes an integer overflow due to conversion to unsigned ([CVE-2021-37645](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37645))
+* Fixes a bad allocation error in `StringNGrams` caused by integer conversion ([CVE-2021-37646](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37646))
+* Fixes a null pointer dereference in `SparseTensorSliceDataset` ([CVE-2021-37647](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37647))
+* Fixes an incorrect validation of `SaveV2` inputs ([CVE-2021-37648](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37648))
+* Fixes a null pointer dereference in `UncompressElement` ([CVE-2021-37649](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37649))
+* Fixes a segfault and a heap buffer overflow in `{Experimental,}DatasetToTFRecord` ([CVE-2021-37650](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37650))
+* Fixes a heap buffer overflow in `FractionalAvgPoolGrad` ([CVE-2021-37651](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37651))
+* Fixes a use after free in boosted trees creation ([CVE-2021-37652](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37652))
+* Fixes a division by 0 in `ResourceGather` ([CVE-2021-37653](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37653))
+* Fixes a heap OOB and a `CHECK` fail in `ResourceGather` ([CVE-2021-37654](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37654))
+* Fixes a heap OOB in `ResourceScatterUpdate` ([CVE-2021-37655](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37655))
+* Fixes an undefined behavior arising from reference binding to nullptr in `RaggedTensorToSparse` ([CVE-2021-37656](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37656))
+* Fixes an undefined behavior arising from reference binding to nullptr in `MatrixDiagV*` ops ([CVE-2021-37657](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37657))
+* Fixes an undefined behavior arising from reference binding to nullptr in `MatrixSetDiagV*` ops ([CVE-2021-37658](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37658))
+* Fixes an undefined behavior arising from reference binding to nullptr and heap OOB in binary cwise ops ([CVE-2021-37659](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37659))
+* Fixes a division by 0 in inplace operations ([CVE-2021-37660](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37660))
+* Fixes a crash caused by integer conversion to unsigned ([CVE-2021-37661](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37661))
+* Fixes an undefined behavior arising from reference binding to nullptr in boosted trees ([CVE-2021-37662](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37662))
+* Fixes a heap OOB in boosted trees ([CVE-2021-37664](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37664))
+* Fixes vulnerabilities arising from incomplete validation in `QuantizeV2` ([CVE-2021-37663](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37663))
+* Fixes vulnerabilities arising from incomplete validation in MKL requantization ([CVE-2021-37665](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37665))
+* Fixes an undefined behavior arising from reference binding to nullptr in `RaggedTensorToVariant` ([CVE-2021-37666](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37666))
+* Fixes an undefined behavior arising from reference binding to nullptr in unicode encoding ([CVE-2021-37667](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37667))
+* Fixes an FPE in `tf.raw_ops.UnravelIndex` ([CVE-2021-37668](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37668))
+* Fixes a crash in NMS ops caused by integer conversion to unsigned ([CVE-2021-37669](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37669))
+* Fixes a heap OOB in `UpperBound` and `LowerBound` ([CVE-2021-37670](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37670))
+* Fixes an undefined behavior arising from reference binding to nullptr in map operations ([CVE-2021-37671](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37671))
+* Fixes a heap OOB in `SdcaOptimizerV2` ([CVE-2021-37672](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37672))
+* Fixes a `CHECK`-fail in `MapStage` ([CVE-2021-37673](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37673))
+* Fixes a vulnerability arising from incomplete validation in `MaxPoolGrad` ([CVE-2021-37674](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37674))
+* Fixes an undefined behavior arising from reference binding to nullptr in shape inference ([CVE-2021-37676](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37676))
+* Fixes a division by 0 in most convolution operators ([CVE-2021-37675](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37675))
+* Fixes vulnerabilities arising from missing validation in shape inference for `Dequantize` ([CVE-2021-37677](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37677))
+* Fixes an arbitrary code execution due to YAML deserialization ([CVE-2021-37678](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37678))
+* Fixes a heap OOB in nested `tf.map_fn` with `RaggedTensor`s ([CVE-2021-37679](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37679))
+* Fixes a division by zero in TFLite ([CVE-2021-37680](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37680))
+* Fixes an NPE in TFLite ([CVE-2021-37681](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37681))
+* Fixes a vulnerability arising from use of unitialized value in TFLite ([CVE-2021-37682](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37682))
+* Fixes an FPE in TFLite division operations ([CVE-2021-37683](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37683))
+* Fixes an FPE in TFLite pooling operations ([CVE-2021-37684](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37684))
+* Fixes an infinite loop in TFLite ([CVE-2021-37686](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37686))
+* Fixes a heap OOB in TFLite ([CVE-2021-37685](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37685))
+* Fixes a heap OOB in TFLite's `Gather*` implementations ([CVE-2021-37687](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37687))
+* Fixes an undefined behavior arising from null pointer dereference in TFLite ([CVE-2021-37688](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37688))
+* Fixes an undefined behavior arising from null pointer dereference in TFLite MLIR optimizations ([CVE-2021-37689](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37689))
+* Fixes a FPE in LSH in TFLite ([CVE-2021-37691](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37691))
+* Fixes a segfault on strings tensors with mismatched dimensions, arising in Go code ([CVE-2021-37692](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37692))
+* Fixes a use after free and a potential segfault in shape inference functions ([CVE-2021-37690](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37690))
+* Updates `curl` to `7.77.0` to handle [CVE-2021-22876](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22876), [CVE-2021-22897](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22897), [CVE-2021-22898](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22898), and [CVE-2021-22901](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22901).
-*
-*
-*
+# Release 2.5.0
## Major Features and Improvements
-*
-*
-
+* Support for Python3.9 has been added.
* TPU embedding support
* Added `profile_data_directory` to `EmbeddingConfigSpec` in
`_tpu_estimator_embedding.py`. This allows embedding lookup statistics
@@ -60,31 +209,48 @@
* `tf.distribute.experimental.ParameterServerStrategy` now supports
training with Keras `Model.fit` when used with `DatasetCreator`.
* PluggableDevice
- * Third-party devices can now connect to TensorFlow
- [modularly](https://github.com/tensorflow/community/blob/master/rfcs/20190305-modular-tensorflow.md)
- through [StreamExecutor C API](https://github.com/tensorflow/community/blob/master/rfcs/20200612-stream-executor-c-api.md).
+ * Third-party devices can now connect to TensorFlow as plug-ins through
+ [StreamExecutor C API](https://github.com/tensorflow/community/blob/master/rfcs/20200612-stream-executor-c-api.md).
and [PluggableDevice](https://github.com/tensorflow/community/blob/master/rfcs/20200624-pluggable-device-for-tensorflow.md) interface.
* Add custom ops and kernels through
[kernel and op registration C API](https://github.com/tensorflow/community/blob/master/rfcs/20190814-kernel-and-op-registration.md).
* Register custom graph optimization passes with
- [graph optimization C API](https://github.com/tensorflow/community/blob/master/rfcs/20201027-modular-tensorflow-graph-c-api.md).
-* [oneAPI Deep Neural Network Library (oneDNN)](https://github.com/oneapi-src/oneDNN)
+ [graph optimization C API](https://github.com/tensorflow/community/blob/master/rfcs/20201027-modular-tensorflow-graph-c-api.md).
+* [oneAPI Deep Neural Network Library (oneDNN)](https://github.com/oneapi-src/oneDNN)
CPU performance optimizations from
[Intel-optimized TensorFlow](https://software.intel.com/content/www/us/en/develop/articles/intel-optimization-for-tensorflow-installation-guide.html)
- are now available in the official x86-64 Linux and Windows builds.
+ are now available in the official x86-64 Linux and Windows builds.
* They are off by default. Enable them by setting the environment variable
`TF_ENABLE_ONEDNN_OPTS=1`.
* We do not recommend using them in GPU systems, as they have not been
sufficiently tested with GPUs yet.
+* TensorFlow pip packages are now built with CUDA11.2 and cuDNN 8.1.0
+
+## Breaking Changes
+
+* The `TF_CPP_MIN_VLOG_LEVEL` environment variable has been renamed to to
+ `TF_CPP_MAX_VLOG_LEVEL` which correctly describes its effect.
## Bug Fixes and Other Changes
-*
-*
-*
* `tf.keras`:
- * Improvements to Keras preprocessing layers:
- * Discretization combiner implemented, with additional arg `epsilon`.
+ * Preprocessing layers API consistency changes:
+ * `StringLookup` added `output_mode`, `sparse`, and
+ `pad_to_max_tokens` arguments with same semantics as
+ `TextVectorization`.
+ * `IntegerLookup` added `output_mode`, `sparse`, and
+ `pad_to_max_tokens` arguments with same semantics as
+ `TextVectorization`. Renamed `max_values`, `oov_value` and
+ `mask_value` to `max_tokens`, `oov_token` and `mask_token` to align
+ with `StringLookup` and `TextVectorization`.
+ * `TextVectorization` default for `pad_to_max_tokens` switched to
+ False.
+ * `CategoryEncoding` no longer supports `adapt`, `IntegerLookup`
+ now supports equivalent functionality. `max_tokens` argument renamed
+ to `num_tokens`.
+ * `Discretization` added `num_bins` argument for learning bins
+ boundaries through calling `adapt` on a dataset. Renamed `bins`
+ argument to `bin_boundaries` for specifying bins without `adapt`.
* Improvements to model saving/loading:
* `model.load_weights` now accepts paths to saved models.
* Keras inputs can now be created directly from arbitrary `tf.TypeSpecs`.
@@ -108,6 +274,7 @@
the input pipeline to insert sharding transformations.
* Make tf.data.Options persistent across `tf.function` and `GraphDef`
boundaries.
+
* XLA compilation:
* `tf.function(experimental_compile=True)` has become a stable API,
renamed `tf.function(jit_compile=True)`.
@@ -157,7 +324,7 @@
ML authoring is generally discouraged.
* Add support for static hash tables through
`TFLiteConverter.from_saved_model`.
- * The Python TF Lite Interpreter bindings now have an option
+ * The Python TF Lite Interpreter bindings now has an option
`experimental_preserve_all_tensors` to aid in debugging conversion.
* Quantized x86 execution defaults to Ruy GEMM library for platforms with
AVX support.
@@ -175,7 +342,7 @@
`tf.GradientTape` inside a `tf.function`.
* Changed the default step size in `gradient_checker_v2.compute_gradients` to be exactly representable as a binary floating point numbers. This avoids poluting gradient approximations needlessly, which is some cases leads to false negatives in op gradient tests.
* Added `tf.config.experimental.get_memory_info`, returning a dict with the
- current and peak memory usage. Deprecated
+ current and peak memory usage. Deprecated
`tf.config.experimental.get_memory_usage` in favor of this new function.
* Extended `tf.config.experimental.enable_tensor_float_32_execution` to
control Tensor-Float-32 evaluation in RNNs.
@@ -185,9 +352,9 @@
https://github.com/abseil/abseil-cpp/blob/master/absl/status/status.h
* `tf.summary`:
- * New `tf.summary.graph` allows manual write of TensorFlow graph
- (`tf.Graph` or `tf.compat.v1.GraphDef`) as a summary. This is not a
- replacement for the trace-based API.
+ * New `tf.summary.graph` allows manual write of TensorFlow graph
+ (`tf.Graph` or `tf.compat.v1.GraphDef`) as a summary. This is not a
+ replacement for the trace-based API.
* Set `/d2ReducedOptimizeHugeFunctions` by default for Windows builds. This
provides a big compile-time speedup, and effectively raises the minimum
@@ -221,10 +388,149 @@
the MLIR bridge in a \"safe\" mode. This runs the MLIR bridge in a
FallbackEnabled mode when an analysis of the graph determines
that the graph does not have unsupported features.
+* Deterministic Op Functionality:
+ * Add determinism-unimplemented exception-throwing to the segment-sum ops.
+ When the environment variable `TF_DETERMINISTIC_OPS` is set to `"true"`
+ or `"1"` (when op-determinism is expected), an attempt to run the
+ folowing ops on a GPU will throw `tf.errors.UnimplementedError` (with an
+ understandable message) when `data` is a floating-point type, including
+ complex types (if supported): `tf.math.segment_prod`,
+ `tf.math.segment_sum`, `tf.math.unsorted_segment_mean`,
+ `tf.math.unsorted_segment_sqrt_n`, `tf.math.unsorted_segment_prod`,
+ `tf.math.unsorted_segment_sum`, and therefore also
+ `tf.convert_to_tensor` when `value` is of type `tf.IndexedSlices` (such
+ as in the backprop though `tf.gather` into a dense embedding). See
+ issue [39751](https://github.com/tensorflow/tensorflow/issues/39751)
+ which this change addresses, but does not solve. This exception-throwing
+ behavior can be disabled by setting the environment variable
+ `TF_DISABLE_SEGMENT_REDUCTION_OP_DETERMINISM_EXCEPTIONS` to `"true"` or
+ `"1"`. For more information about these changes, see the description in
+ pull request
+ [47772](https://github.com/tensorflow/tensorflow/pull/47772).
+ * In previous versions of TensorFlow, when a GPU was available,
+ `tf.sparse.sparse_dense_matmul` introduced truly random noise in the
+ forward path for data of type `tf.float32` but not for data of type
+ `tf.float64` (for which there was no GPU implementation). In this
+ current release, GPU support for other floating-point types
+ (`tf.float16`, `tf.float64`, `tf.complex64`, and `tf.complex128`) has
+ been added for this op. If you were relying on the determinism of the
+ `tf.float64` CPU implementation being automatically selected because of
+ the absence of the `tf.float64` GPU implementation, you with either
+ need to force the op to run on the CPU or use a different data type.
+* Security
+ * Fixes a heap buffer overflow in `RaggedBinCount` ([CVE-2021-29512](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29512))
+ * Fixes a heap out of bounds write in `RaggedBinCount` ([CVE-2021-29514](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29514))
+ * Fixes a type confusion during tensor casts which leads to dereferencing null pointers ([CVE-2021-29513](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29513))
+ * Fixes a reference binding to null pointer in `MatrixDiag*` ops ([CVE-2021-29515](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29515))
+ * Fixes a null pointer dereference via invalid Ragged Tensors ([CVE-2021-29516](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29516))
+ * Fixes a division by zero in `Conv3D` ([CVE-2021-29517](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29517))
+ * Fixes vulnerabilities where session operations in eager mode lead to null pointer dereferences ([CVE-2021-29518](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29518))
+ * Fixes a `CHECK`-fail in `SparseCross` caused by type confusion ([CVE-2021-29519](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29519))
+ * Fixes a segfault in `SparseCountSparseOutput` ([CVE-2021-29521](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29521))
+ * Fixes a heap buffer overflow in `Conv3DBackprop*` ([CVE-2021-29520](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29520))
+ * Fixes a division by 0 in `Conv3DBackprop*` ([CVE-2021-29522](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29522))
+ * Fixes a `CHECK`-fail in `AddManySparseToTensorsMap` ([CVE-2021-29523](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29523))
+ * Fixes a division by 0 in `Conv2DBackpropFilter` ([CVE-2021-29524](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29524))
+ * Fixes a division by 0 in `Conv2DBackpropInput` ([CVE-2021-29525](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29525))
+ * Fixes a division by 0 in `Conv2D` ([CVE-2021-29526](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29526))
+ * Fixes a division by 0 in `QuantizedConv2D` ([CVE-2021-29527](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29527))
+ * Fixes a division by 0 in `QuantizedMul` ([CVE-2021-29528](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29528))
+ * Fixes vulnerabilities caused by invalid validation in `SparseMatrixSparseCholesky` ([CVE-2021-29530](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29530))
+ * Fixes a heap buffer overflow caused by rounding ([CVE-2021-29529](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29529))
+ * Fixes a `CHECK`-fail in `tf.raw_ops.EncodePng` ([CVE-2021-29531](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29531))
+ * Fixes a heap out of bounds read in `RaggedCross` ([CVE-2021-29532](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29532))
+ * Fixes a `CHECK`-fail in `DrawBoundingBoxes` ([CVE-2021-29533](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29533))
+ * Fixes a heap buffer overflow in `QuantizedMul` ([CVE-2021-29535](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29535))
+ * Fixes a `CHECK`-fail in `SparseConcat` ([CVE-2021-29534](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29534))
+ * Fixes a heap buffer overflow in `QuantizedResizeBilinear` ([CVE-2021-29537](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29537))
+ * Fixes a heap buffer overflow in `QuantizedReshape` ([CVE-2021-29536](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29536))
+ * Fixes a division by zero in `Conv2DBackpropFilter` ([CVE-2021-29538](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29538))
+ * Fixes a heap buffer overflow in `Conv2DBackpropFilter` ([CVE-2021-29540](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29540))
+ * Fixes a heap buffer overflow in `StringNGrams` ([CVE-2021-29542](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29542))
+ * Fixes a null pointer dereference in `StringNGrams` ([CVE-2021-29541](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29541))
+ * Fixes a `CHECK`-fail in `QuantizeAndDequantizeV4Grad` ([CVE-2021-29544](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29544))
+ * Fixes a `CHECK`-fail in `CTCGreedyDecoder` ([CVE-2021-29543](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29543))
+ * Fixes a heap buffer overflow in `SparseTensorToCSRSparseMatrix` ([CVE-2021-29545](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29545))
+ * Fixes a division by 0 in `QuantizedBiasAdd` ([CVE-2021-29546](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29546))
+ * Fixes a heap out of bounds in `QuantizedBatchNormWithGlobalNormalization` ([CVE-2021-29547](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29547))
+ * Fixes a division by 0 in `QuantizedBatchNormWithGlobalNormalization` ([CVE-2021-29548](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29548))
+ * Fixes a division by 0 in `QuantizedAdd` ([CVE-2021-29549](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29549))
+ * Fixes a division by 0 in `FractionalAvgPool` ([CVE-2021-29550](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29550))
+ * Fixes an OOB read in `MatrixTriangularSolve` ([CVE-2021-29551](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29551))
+ * Fixes a heap OOB in `QuantizeAndDequantizeV3` ([CVE-2021-29553](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29553))
+ * Fixes a `CHECK`-failure in `UnsortedSegmentJoin` ([CVE-2021-29552](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29552))
+ * Fixes a division by 0 in `DenseCountSparseOutput` ([CVE-2021-29554](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29554))
+ * Fixes a division by 0 in `FusedBatchNorm` ([CVE-2021-29555](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29555))
+ * Fixes a division by 0 in `SparseMatMul` ([CVE-2021-29557](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29557))
+ * Fixes a division by 0 in `Reverse` ([CVE-2021-29556](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29556))
+ * Fixes a heap buffer overflow in `SparseSplit` ([CVE-2021-29558](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29558))
+ * Fixes a heap OOB access in unicode ops ([CVE-2021-29559](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29559))
+ * Fixes a heap buffer overflow in `RaggedTensorToTensor` ([CVE-2021-29560](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29560))
+ * Fixes a `CHECK`-fail in `LoadAndRemapMatrix` ([CVE-2021-29561](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29561))
+ * Fixes a `CHECK`-fail in `tf.raw_ops.IRFFT` ([CVE-2021-29562](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29562))
+ * Fixes a `CHECK`-fail in `tf.raw_ops.RFFT` ([CVE-2021-29563](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29563))
+ * Fixes a null pointer dereference in `EditDistance` ([CVE-2021-29564](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29564))
+ * Fixes a null pointer dereference in `SparseFillEmptyRows` ([CVE-2021-29565](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29565))
+ * Fixes a heap OOB access in `Dilation2DBackpropInput` ([CVE-2021-29566](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29566))
+ * Fixes a reference binding to null in `ParameterizedTruncatedNormal` ([CVE-2021-29568](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29568))
+ * Fixes a set of vulnerabilities caused by lack of validation in `SparseDenseCwiseMul` ([CVE-2021-29567](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29567))
+ * Fixes a heap out of bounds read in `MaxPoolGradWithArgmax` ([CVE-2021-29570](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29570))
+ * Fixes a heap out of bounds read in `RequantizationRange` ([CVE-2021-29569](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29569))
+ * Fixes a memory corruption in `DrawBoundingBoxesV2` ([CVE-2021-29571](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29571))
+ * Fixes a reference binding to nullptr in `SdcaOptimizer` ([CVE-2021-29572](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29572))
+ * Fixes an overflow and a denial of service in `tf.raw_ops.ReverseSequence` ([CVE-2021-29575](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29575))
+ * Fixes a division by 0 in `MaxPoolGradWithArgmax` ([CVE-2021-29573](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29573))
+ * Fixes an undefined behavior in `MaxPool3DGradGrad` ([CVE-2021-29574](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29574))
+ * Fixes a heap buffer overflow in `MaxPool3DGradGrad` ([CVE-2021-29576](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29576))
+ * Fixes a heap buffer overflow in `AvgPool3DGrad` ([CVE-2021-29577](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29577))
+ * Fixes an undefined behavior and a `CHECK`-fail in `FractionalMaxPoolGrad` ([CVE-2021-29580](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29580))
+ * Fixes a heap buffer overflow in `FractionalAvgPoolGrad` ([CVE-2021-29578](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29578))
+ * Fixes a heap buffer overflow in `MaxPoolGrad` ([CVE-2021-29579](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29579))
+ * Fixes a segfault in `CTCBeamSearchDecoder` ([CVE-2021-29581](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29581))
+ * Fixes a heap OOB read in `tf.raw_ops.Dequantize` ([CVE-2021-29582](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29582))
+ * Fixes a `CHECK`-fail due to integer overflow ([CVE-2021-29584](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29584))
+ * Fixes a heap buffer overflow and undefined behavior in `FusedBatchNorm` ([CVE-2021-29583](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29583))
+ * Fixes a division by zero in padding computation in TFLite ([CVE-2021-29585](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29585))
+ * Fixes a division by zero in optimized pooling implementations in TFLite ([CVE-2021-29586](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29586))
+ * Fixes a division by zero in TFLite's implementation of `SpaceToDepth` ([CVE-2021-29587](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29587))
+ * Fixes a division by zero in TFLite's implementation of `GatherNd` ([CVE-2021-29589](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29589))
+ * Fixes a division by zero in TFLite's implementation of `TransposeConv` ([CVE-2021-29588](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29588))
+ * Fixes a heap OOB read in TFLite's implementation of `Minimum` or `Maximum` ([CVE-2021-29590](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29590))
+ * Fixes a null pointer dereference in TFLite's `Reshape` operator ([CVE-2021-29592](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29592))
+ * Fixes a stack overflow due to looping TFLite subgraph ([CVE-2021-29591](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29591))
+ * Fixes a division by zero in TFLite's implementation of `DepthToSpace` ([CVE-2021-29595](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29595))
+ * Fixes a division by zero in TFLite's convolution code ([CVE-2021-29594](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29594))
+ * Fixes a division by zero in TFLite's implementation of `EmbeddingLookup` ([CVE-2021-29596](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29596))
+ * Fixes a division by zero in TFLite's implementation of `BatchToSpaceNd` ([CVE-2021-29593](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29593))
+ * Fixes a division by zero in TFLite's implementation of `SpaceToBatchNd` ([CVE-2021-29597](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29597))
+ * Fixes a division by zero in TFLite's implementation of `SVDF` ([CVE-2021-29598](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29598))
+ * Fixes a division by zero in TFLite's implementation of `Split` ([CVE-2021-29599](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29599))
+ * Fixes a division by zero in TFLite's implementation of `OneHot` ([CVE-2021-29600](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29600))
+ * Fixes a division by zero in TFLite's implementation of `DepthwiseConv` ([CVE-2021-29602](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29602))
+ * Fixes a division by zero in TFLite's implementation of hashtable lookup ([CVE-2021-29604](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29604))
+ * Fixes a integer overflow in TFLite concatentation ([CVE-2021-29601](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29601))
+ * Fixes a integer overflow in TFLite memory allocation ([CVE-2021-29605](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29605))
+ * Fixes a heap OOB write in TFLite ([CVE-2021-29603](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29603))
+ * Fixes a heap OOB read in TFLite ([CVE-2021-29606](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29606))
+ * Fixes a heap OOB and null pointer dereference in `RaggedTensorToTensor` ([CVE-2021-29608](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29608))
+ * Fixes vulnerabilities caused by incomplete validation in `SparseAdd` ([CVE-2021-29609](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29609))
+ * Fixes vulnerabilities caused by incomplete validation in `SparseSparseMinimum` ([CVE-2021-29607](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29607))
+ * Fixes vulnerabilities caused by incomplete validation in `SparseReshape` ([CVE-2021-29611](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29611))
+ * Fixes vulnerabilities caused by invalid validation in `QuantizeAndDequantizeV2` ([CVE-2021-29610](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29610))
+ * Fixes a heap buffer overflow in `BandedTriangularSolve` ([CVE-2021-29612](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29612))
+ * Fixes vulnerabilities caused by incomplete validation in `tf.raw_ops.CTCLoss` ([CVE-2021-29613](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29613))
+ * Fixes an interpreter crash from vulnerabilities in `tf.io.decode_raw` ([CVE-2021-29614](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29614))
+ * Fixes a stack overflow in `ParseAttrValue` with nested tensors ([CVE-2021-29615](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29615))
+ * Fixes a null dereference in Grappler's `TrySimplify` ([CVE-2021-29616](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29616))
+ * Fixes a crash in `tf.transpose` with complex inputs ([CVE-2021-29618](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29618))
+ * Fixes a crash in `tf.strings.substr` due to `CHECK`-fail ([CVE-2021-29617](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29617))
+ * Fixes a segfault in `tf.raw_ops.SparseCountSparseOutput` ([CVE-2021-29619](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29619))
+ * Fixes a segfault in `tf.raw_ops.ImmutableConst` ([CVE-2021-29539](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29539))
+ * Updates `curl` to `7.76.0` to handle [CVE-2020-8169](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8169), [CVE-2020-8177](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8177), [CVE-2020-8231](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8231), [CVE-2020-8284](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8284), [CVE-2020-8285](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8285) and [CVE-2020-8286](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8286).
* Other
- * Adding show_debug_info to mlir.convert_graph_def and
- mlir.convert_function.
+ * Added `show_debug_info` to `mlir.convert_graph_def` and
+ `mlir.convert_function`.
* Added [Arm Compute Library (ACL)](https://github.com/ARM-software/ComputeLibrary)
support to `--config=mkl_aarch64` build.
@@ -232,7 +538,7 @@
This release contains contributions from many people at Google, as well as:
-, , , , ,
+8bitmp3, Aaron S. Mondal, Abhilash Mahendrakar, Abhinav Upadhyay, Abhishek Kulkarni, Abolfazl Shahbazi, Adam Hillier, Aditya Kane, Ag Ramesh, ahmedsabie, Albert Villanova Del Moral, Aleksey Vitebskiy, Alex Hoffman, Alexander Bayandin, Alfie Edwards, Aman Kishore, Amogh Joshi, andreABbauer, Andrew Goodbody, Andrzej Pomirski, Artemiy Ryabinkov, Ashish Jha, ather, Ayan Moitra, Bairen Yi, Bart Ribbers, Bas Aarts, Behzad Abghari, Ben Arnao, Ben Barsdell, Benjamin Klimczak, bhack, Brendan Collins, Can Wang, Cheng Ren, Chris Leary, Chris Olivier, Clemens Giuliani, Cloud Han, Corey Cole, Cui, Yifeng, Cuong V. Nguyen, Daniel Moore, Dawid Wojciechowski, Ddavis-2015, Dean Wyatte, Denisa Roberts, dependabot[bot], Dmitry Volodin, Dominic Jack, Duncan Riach, dushuai, Elena Zhelezina, Eli Osherovich, Erik Smistad, ewsn1593, Felix Fent, fo40225, François Chollet, Frederic Bastien, Freedom" Koan-Sin Tan, fsx950223, ganand1, gbaned, Georgiy Manuilov, gerbauz, Guillaume Klein, Guozhong Zhuang, Harry Slatyer, Harsh188, henri, Henri Woodcock, Hiran Sarkar, Hollow Man, Håkon Sandsmark, I Wayan Dharmana, icysapphire, Ikko Ashimine, Jab Hofmeier, Jack Hessel, Jacob Valdez, Jakub Jatczak, James Bernardi, Jared Smolens, Jason Zaman, jedlimlx, Jenny Plunkett, Jens Elofsson, Jerry Shih, jgehw, Jia Fu Low, Jim Fisher, jpodivin, Julien Stephan, Jungsub Lim, Junha Park, Junhyuk So, justkw, Kaixi Hou, kashyapraval, Kasra Bigdeli, Kazuaki Ishizaki, Keith Mok, Kevin Cheng, kopytjuk, Kristian Hartikainen, ksood12345, Kulin Seth, kushanam, latyas, Lequn Chen, Leslie-Fang, Long M. Lưu, Lukas Geiger, machineko, Mahmoud Abuzaina, Manish, Mao Yunfei, Maozhou, Ge, Marcin Juszkiewicz, Marcin Owsiany, Marconi Jiang, Marcos Pereira, Maria Romanenko Vexlard, Maria Vexlard, Marius Brehler, marload, Martin Kubovčík, Matej, Mateusz Holenko, Maxiwell S. Garcia, Mazhar, mazharul, mbhuiyan, mdfaijul, Michael Gielda, Michael Kuchnik, Michal Szutenberg, Mikhail Stepanov, Milan Straka, Mitchel Humpherys, Mohamed Moselhy, Mohamed Nour Abouelseoud, Måns Bermell, Måns Nilsson, Nathan Luehr, Nico Jahn, Niroop Ammbashankar, Oceania2018, Omri Steiner, Orivej Desh, Oskar Flordal, oujiafan, Patrik Laurell, Paul B. Isaac'S, Paul Klinger, Pawel Piskorski, Pedro Marques, Phat Tran, Piotr Zierhoffer, piyushdatta, Pnikam-Cad, Prashant Kumar, Prateek Gupta, PratsBhatt, Pravin Karandikar, qqq.jq, QQ喵, Quintin, Rama Ketineni, ravikyram, Rehan Guha, rhdong, rmothukuru, Roger Cheng, Rohit Santhanam, rposts, Rsanthanam-Amd, rsun, Rsun-Bdti, Ryan Kuester, ryanking13, Saduf2019, Sami Kama, Samuel Marks, Scott Tseng, Sean Moriarity, Sergey Popov, Sergii Khomenko, Sheng, Yang, shwetaoj, Sidong-Wei, Simon Maurer, Simrit Kaur, Srini511, Srinivasan Narayanamoorthy, Stephan, Stephen Matthews, Sungmann Cho, Sunoru, Suraj Sudhir, Suraj Upadhyay, Taebum Kim, Takayoshi Koizumi, Tamas Bela Feher, Teng Lu, Thibaut Goetghebuer-Planchon, Tomwildenhain-Microsoft, Tony, Traun Leyden, Trent Lo, TVLIgnacy, Tzu-Wei Sung, vaibhav, Vignesh Kothapalli, Vikram Dattu, viktprog, Vinayaka Bandishti, Vincent Abriou, Vishakha Agrawal, Vivek Panyam, Vladimir Silyaev, Võ Văn Nghĩa, wamuir, Wang, Yanzhang, wangsiyu, Waqar Hameed, wxinix, Xiao Yang, xiaohong1031, Xiaoming (Jason) Cui, Xinan Jiang, Yair Ehrenwald, Yajush Vyas, Yasir Modak, Yimei Sun, Yong Tang, Yosshi999, youshenmebutuo, yqtianust, Yuan Tang, yuanbopeng, Yuriy Chernyshov, Yuta Fukasawa, Zachary Deane-Mayer, Zeno Gantner, Zhoulong Jiang, zhuyie, zilinzhu, 彭震东
# Release 2.4.1
diff --git a/tensorflow/cc/saved_model/loader.cc b/tensorflow/cc/saved_model/loader.cc
index dcd652d9fdf3d6..dcab34cc965e0f 100644
--- a/tensorflow/cc/saved_model/loader.cc
+++ b/tensorflow/cc/saved_model/loader.cc
@@ -23,6 +23,7 @@ limitations under the License.
#include "tensorflow/core/framework/attr_value.pb.h"
#include "tensorflow/core/framework/function.pb.h"
#include "tensorflow/core/framework/node_def.pb.h"
+#include "tensorflow/core/framework/op_def.pb.h"
#include "tensorflow/core/framework/tensor.pb.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/lib/monitoring/counter.h"
@@ -95,6 +96,19 @@ static Status ValidateNode(const NodeDef& node) {
return Status::OK();
}
+static Status ValidateFunctionNotRecursive(const FunctionDef& function) {
+ const auto& function_name = function.signature().name();
+ for (const auto& node : function.node_def()) {
+ if (node.op() == function_name) {
+ return errors::FailedPrecondition(
+ "Function ", function_name,
+ " is self recursive and TensorFlow does not support this scenario.");
+ }
+ }
+
+ return Status::OK();
+}
+
static Status ValidateSavedTensors(const GraphDef& graph_def) {
for (const auto& node : graph_def.node()) {
TF_RETURN_IF_ERROR(ValidateNode(node));
@@ -106,6 +120,10 @@ static Status ValidateSavedTensors(const GraphDef& graph_def) {
for (const auto& node : function.node_def()) {
TF_RETURN_IF_ERROR(ValidateNode(node));
}
+
+ // Also check that there is no recursivity in the library
+ // TODO(mihaimaruseac): Do more than self-recursivity
+ TF_RETURN_IF_ERROR(ValidateFunctionNotRecursive(function));
}
}
diff --git a/tensorflow/cc/saved_model/loader_util.cc b/tensorflow/cc/saved_model/loader_util.cc
index 100cae2291333f..411dc41fd44837 100644
--- a/tensorflow/cc/saved_model/loader_util.cc
+++ b/tensorflow/cc/saved_model/loader_util.cc
@@ -34,9 +34,14 @@ Status GetInitOp(const string& export_dir, const MetaGraphDef& meta_graph_def,
const auto& init_op_sig_it =
meta_graph_def.signature_def().find(kSavedModelInitOpSignatureKey);
if (init_op_sig_it != sig_def_map.end()) {
- *init_op_name = init_op_sig_it->second.outputs()
- .find(kSavedModelInitOpSignatureKey)
- ->second.name();
+ const auto& sig_def_outputs = init_op_sig_it->second.outputs();
+ const auto& sig_def_outputs_it =
+ sig_def_outputs.find(kSavedModelInitOpSignatureKey);
+ if (sig_def_outputs_it == sig_def_outputs.end()) {
+ return errors::FailedPrecondition("Could not find output ",
+ kSavedModelInitOpSignatureKey);
+ }
+ *init_op_name = sig_def_outputs_it->second.name();
return Status::OK();
}
diff --git a/tensorflow/compiler/mlir/lite/tests/modify_io_nodes.mlir b/tensorflow/compiler/mlir/lite/tests/modify_io_nodes.mlir
index 32713012ad4ef6..144ab70baca6e4 100644
--- a/tensorflow/compiler/mlir/lite/tests/modify_io_nodes.mlir
+++ b/tensorflow/compiler/mlir/lite/tests/modify_io_nodes.mlir
@@ -2,7 +2,7 @@
// RUN: tf-opt %s -tfl-modify-io-nodes -tfl-test-io-types="int8,int8" | FileCheck --check-prefix=INT8 %s
// RUN: tf-opt %s -tfl-modify-io-nodes -tfl-test-io-types="uint8,uint8" | FileCheck --check-prefix=UINT8 %s
-func @main(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x401408xf32> {
+func @modified(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x401408xf32> {
%cst = constant dense<[1, 401408]> : tensor<2xi32>
%0 = "tfl.quantize"(%arg0) {qtype = tensor<1x224x224x3x!quant.uniform>} : (tensor<1x224x224x3xf32>) -> tensor<1x224x224x3x!quant.uniform>
%1 = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>
@@ -13,7 +13,7 @@ func @main(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x401408xf32> {
%6 = "tfl.dequantize"(%5) : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408xf32>
return %6 : tensor<1x401408xf32>
-// CHECK-LABEL: func @main(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x401408xf32> {
+// CHECK-LABEL: func @modified(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x401408xf32> {
// CHECK-NEXT: %[[shape:.*]] = constant dense<[1, 401408]> : tensor<2xi32>
// CHECK-NEXT: %[[q:.*]] = "tfl.quantize"(%arg0) {qtype = tensor<1x224x224x3x!quant.uniform>} : (tensor<1x224x224x3xf32>) -> tensor<1x224x224x3x!quant.uniform>
// CHECK-NEXT: %[[cst1:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>
@@ -24,7 +24,7 @@ func @main(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x401408xf32> {
// CHECK-NEXT: %[[dq:.*]] = "tfl.dequantize"(%[[softmax]]) : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408xf32>
// CHECK-NEXT: return %[[dq]] : tensor<1x401408xf32>
-// INT8-LABEL: @main(%arg0: tensor<1x224x224x3x!quant.uniform>) -> tensor<1x401408x!quant.uniform> {
+// INT8-LABEL: @modified(%arg0: tensor<1x224x224x3x!quant.uniform>) -> tensor<1x401408x!quant.uniform> {
// INT8-NEXT: %[[shape:.*]] = constant dense<[1, 401408]> : tensor<2xi32>
// INT8-NEXT: %[[cst1:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>
// INT8-NEXT: %[[cst2:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform>, value = dense<0> : tensor<32xi32>} : () -> tensor<32x!quant.uniform>
@@ -33,7 +33,7 @@ func @main(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x401408xf32> {
// INT8-NEXT: %[[softmax:.*]] = "tfl.softmax"(%[[reshape]]) {beta = 1.000000e+00 : f32} : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408x!quant.uniform>
// INT8-NEXT: return %[[softmax]] : tensor<1x401408x!quant.uniform>
-// UINT8-LABEL: func @main(%arg0: tensor<1x224x224x3x!quant.uniform>) -> tensor<1x401408x!quant.uniform> {
+// UINT8-LABEL: func @modified(%arg0: tensor<1x224x224x3x!quant.uniform>) -> tensor<1x401408x!quant.uniform> {
// UINT8-NEXT: %[[shape:.*]] = constant dense<[1, 401408]> : tensor<2xi32>
// UINT8-NEXT: %[[q:.*]] = "tfl.quantize"(%arg0) {qtype = tensor<1x224x224x3x!quant.uniform>} : (tensor<1x224x224x3x!quant.uniform>) -> tensor<1x224x224x3x!quant.uniform>
// UINT8-NEXT: %[[cst1:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>
@@ -44,3 +44,47 @@ func @main(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x401408xf32> {
// UINT8-NEXT: %[[dq:.*]] = "tfl.quantize"(%[[softmax]]) {qtype = tensor<1x401408x!quant.uniform>} : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408x!quant.uniform>
// UINT8-NEXT: return %[[dq]] : tensor<1x401408x!quant.uniform>
}
+
+func @not_modified(%arg0: tensor, %arg1: tensor<1x224x224x3xf32>) -> (tensor<1x401408xf32>, tensor<1x224x224x3xf32>) {
+ %cst = constant dense<[1, 401408]> : tensor<2xi32>
+ %0 = "tfl.quantize"(%arg1) {qtype = tensor<1x224x224x3x!quant.uniform>} : (tensor<1x224x224x3xf32>) -> tensor<1x224x224x3x!quant.uniform>
+ %1 = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>
+ %2 = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform>, value = dense<0> : tensor<32xi32>} : () -> tensor<32x!quant.uniform>
+ %3 = "tfl.conv_2d"(%0, %1, %2) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3x!quant.uniform>, tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>, tensor<32x!quant.uniform>) -> tensor<1x112x112x32x!quant.uniform>
+ %4 = "tfl.reshape"(%3, %cst) : (tensor<1x112x112x32x!quant.uniform>, tensor<2xi32>) -> tensor<1x401408x!quant.uniform>
+ %5 = "tfl.softmax"(%4) {beta = 1.000000e+00 : f32} : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408x!quant.uniform>
+ %6 = "tfl.dequantize"(%5) : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408xf32>
+ return %6, %arg1 : tensor<1x401408xf32>, tensor<1x224x224x3xf32>
+
+// CHECK-LABEL: func @not_modified(%arg0: tensor, %arg1: tensor<1x224x224x3xf32>) -> (tensor<1x401408xf32>, tensor<1x224x224x3xf32>) {
+// CHECK-NEXT: %[[shape:.*]] = constant dense<[1, 401408]> : tensor<2xi32>
+// CHECK-NEXT: %[[q:.*]] = "tfl.quantize"(%arg1) {qtype = tensor<1x224x224x3x!quant.uniform>} : (tensor<1x224x224x3xf32>) -> tensor<1x224x224x3x!quant.uniform>
+// CHECK-NEXT: %[[cst1:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>
+// CHECK-NEXT: %[[cst2:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform>, value = dense<0> : tensor<32xi32>} : () -> tensor<32x!quant.uniform>
+// CHECK-NEXT: %[[conv:.*]] = "tfl.conv_2d"(%[[q]], %[[cst1]], %[[cst2]]) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3x!quant.uniform>, tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>, tensor<32x!quant.uniform>) -> tensor<1x112x112x32x!quant.uniform>
+// CHECK-NEXT: %[[reshape:.*]] = "tfl.reshape"(%[[conv]], %[[shape]]) : (tensor<1x112x112x32x!quant.uniform>, tensor<2xi32>) -> tensor<1x401408x!quant.uniform>
+// CHECK-NEXT: %[[softmax:.*]] = "tfl.softmax"(%[[reshape]]) {beta = 1.000000e+00 : f32} : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408x!quant.uniform>
+// CHECK-NEXT: %[[dq:.*]] = "tfl.dequantize"(%[[softmax]]) : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408xf32>
+// CHECK-NEXT: return %[[dq]], %arg1 : tensor<1x401408xf32>, tensor<1x224x224x3xf32>
+
+// INT8-LABEL: @not_modified(%arg0: tensor, %arg1: tensor<1x224x224x3xf32>) -> (tensor<1x401408x!quant.uniform>, tensor<1x224x224x3xf32>) {
+// INT8-NEXT: %[[shape:.*]] = constant dense<[1, 401408]> : tensor<2xi32>
+// INT8-NEXT: %[[q:.*]] = "tfl.quantize"(%arg1) {qtype = tensor<1x224x224x3x!quant.uniform>} : (tensor<1x224x224x3xf32>) -> tensor<1x224x224x3x!quant.uniform>
+// INT8-NEXT: %[[cst1:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>
+// INT8-NEXT: %[[cst2:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform>, value = dense<0> : tensor<32xi32>} : () -> tensor<32x!quant.uniform>
+// INT8-NEXT: %[[conv:.*]] = "tfl.conv_2d"(%[[q]], %[[cst1]], %[[cst2]]) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3x!quant.uniform>, tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>, tensor<32x!quant.uniform>) -> tensor<1x112x112x32x!quant.uniform>
+// INT8-NEXT: %[[reshape:.*]] = "tfl.reshape"(%[[conv]], %[[shape]]) : (tensor<1x112x112x32x!quant.uniform>, tensor<2xi32>) -> tensor<1x401408x!quant.uniform>
+// INT8-NEXT: %[[softmax:.*]] = "tfl.softmax"(%[[reshape]]) {beta = 1.000000e+00 : f32} : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408x!quant.uniform>
+// INT8-NEXT: return %[[softmax]], %arg1 : tensor<1x401408x!quant.uniform>, tensor<1x224x224x3xf32>
+
+// UINT8-LABEL: func @not_modified(%arg0: tensor, %arg1: tensor<1x224x224x3xf32>) -> (tensor<1x401408x!quant.uniform>, tensor<1x224x224x3xf32>) {
+// UINT8-NEXT: %[[shape:.*]] = constant dense<[1, 401408]> : tensor<2xi32>
+// UINT8-NEXT: %[[q:.*]] = "tfl.quantize"(%arg1) {qtype = tensor<1x224x224x3x!quant.uniform>} : (tensor<1x224x224x3xf32>) -> tensor<1x224x224x3x!quant.uniform>
+// UINT8-NEXT: %[[cst1:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>
+// UINT8-NEXT: %[[cst2:.*]] = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform>, value = dense<0> : tensor<32xi32>} : () -> tensor<32x!quant.uniform>
+// UINT8-NEXT: %[[conv:.*]] = "tfl.conv_2d"(%[[q]], %[[cst1]], %[[cst2]]) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3x!quant.uniform>, tensor<32x3x3x3x!quant.uniform:f32, 0.021826678373682216>>, tensor<32x!quant.uniform>) -> tensor<1x112x112x32x!quant.uniform>
+// UINT8-NEXT: %[[reshape:.*]] = "tfl.reshape"(%[[conv]], %[[shape]]) : (tensor<1x112x112x32x!quant.uniform>, tensor<2xi32>) -> tensor<1x401408x!quant.uniform>
+// UINT8-NEXT: %[[softmax:.*]] = "tfl.softmax"(%[[reshape]]) {beta = 1.000000e+00 : f32} : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408x!quant.uniform>
+// UINT8-NEXT: %[[dq:.*]] = "tfl.quantize"(%[[softmax]]) {qtype = tensor<1x401408x!quant.uniform>} : (tensor<1x401408x!quant.uniform>) -> tensor<1x401408x!quant.uniform>
+// UINT8-NEXT: return %[[dq]], %arg1 : tensor<1x401408x!quant.uniform>, tensor<1x224x224x3xf32>
+}
diff --git a/tensorflow/compiler/mlir/lite/transforms/modify_io_nodes.cc b/tensorflow/compiler/mlir/lite/transforms/modify_io_nodes.cc
index 53ac0b051e1490..bcfca0690ec1af 100644
--- a/tensorflow/compiler/mlir/lite/transforms/modify_io_nodes.cc
+++ b/tensorflow/compiler/mlir/lite/transforms/modify_io_nodes.cc
@@ -135,7 +135,11 @@ LogicalResult ModifyIONodesPass::ModifyInputNodes(
quantize_op.erase();
}
} else {
+ // `arg` has multiple uses or the user isn't a quantiz op (so we couldn't
+ // rewrite it to a different type. Make a copy of the `arg` and replace
+ // its use.
new_arg = block.addArgument(arg_type);
+ arg.replaceAllUsesWith(new_arg);
}
block.eraseArgument(0);
}
diff --git a/tensorflow/compiler/mlir/lite/transforms/optimize.cc b/tensorflow/compiler/mlir/lite/transforms/optimize.cc
index 859e57fd178c2f..e0b3d73cf4e863 100644
--- a/tensorflow/compiler/mlir/lite/transforms/optimize.cc
+++ b/tensorflow/compiler/mlir/lite/transforms/optimize.cc
@@ -65,6 +65,9 @@ constexpr char kRelu6[] = "RELU6";
constexpr char kRelu1[] = "RELU_N1_TO_1";
bool L2NormalizeReduceAxis(Value sq_op, DenseElementsAttr axis) {
+ if (axis.getNumElements() == 0) {
+ return false;
+ }
if (sq_op.getType().cast().getRank() - 1 ==
*axis.getValues().begin() ||
*axis.getValues().begin() == -1) {
diff --git a/tensorflow/compiler/xla/statusor.h b/tensorflow/compiler/xla/statusor.h
index a32e2ad9851b0b..da6fa9a19031d6 100644
--- a/tensorflow/compiler/xla/statusor.h
+++ b/tensorflow/compiler/xla/statusor.h
@@ -21,8 +21,7 @@ limitations under the License.
namespace xla {
// Use steam_executor's StatusOr so we don't duplicate code.
-template
-using StatusOr = ::stream_executor::port::StatusOr;
+using tensorflow::StatusOr; // TENSORFLOW_STATUS_OK
} // namespace xla
diff --git a/tensorflow/core/common_runtime/constant_folding.cc b/tensorflow/core/common_runtime/constant_folding.cc
index 384ec836cdf9b4..64ed1c398ada30 100644
--- a/tensorflow/core/common_runtime/constant_folding.cc
+++ b/tensorflow/core/common_runtime/constant_folding.cc
@@ -30,6 +30,7 @@ limitations under the License.
#include "tensorflow/core/framework/log_memory.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/types.h"
+#include "tensorflow/core/framework/types.pb.h"
#include "tensorflow/core/graph/algorithm.h"
#include "tensorflow/core/graph/node_builder.h"
#include "tensorflow/core/graph/subgraph.h"
@@ -223,7 +224,8 @@ bool IsConstantFoldable(
std::unordered_map>*
shape_replacement_map) {
if (n->IsConstant()) {
- return true;
+ // Skip constant folding resources as they cannot be deep copied.
+ return n->output_type(0) != DT_RESOURCE;
}
if (MaybeReplaceShapeOp(n, shape_map, shape_replacement_map)) {
return true;
diff --git a/tensorflow/core/common_runtime/immutable_executor_state.cc b/tensorflow/core/common_runtime/immutable_executor_state.cc
index 03d12a0e98abd5..6af8c5f74c1eca 100644
--- a/tensorflow/core/common_runtime/immutable_executor_state.cc
+++ b/tensorflow/core/common_runtime/immutable_executor_state.cc
@@ -131,6 +131,7 @@ Status ImmutableExecutorState::Initialize(const Graph& graph) {
Status s = params_.create_kernel(n->properties(), &item->kernel);
if (!s.ok()) {
+ params_.delete_kernel(item->kernel);
item->kernel = nullptr;
s = AttachDef(s, *n);
return s;
@@ -315,6 +316,10 @@ Status ImmutableExecutorState::BuildControlFlowInfo(const Graph* g,
} else if (IsExit(curr_node)) {
// Exit to the parent frame.
parent = parent_nodes[curr_id];
+ if (!parent) {
+ return errors::InvalidArgument(
+ "Invalid Exit op: Cannot find a corresponding Enter op.");
+ }
frame_name = cf_info->frame_names[parent->id()];
parent = parent_nodes[parent->id()];
} else {
diff --git a/tensorflow/core/common_runtime/shape_refiner.cc b/tensorflow/core/common_runtime/shape_refiner.cc
index 375f809b31b369..ec655b2acd0184 100644
--- a/tensorflow/core/common_runtime/shape_refiner.cc
+++ b/tensorflow/core/common_runtime/shape_refiner.cc
@@ -120,9 +120,26 @@ Status ShapeRefiner::InferShapesForFunctionSubNode(
TF_RETURN_IF_ERROR(outer_context->MakeShapeFromShapeProto(proto, &handle));
outer_context->set_output(index, handle);
- auto* resource = node_context->input_handle_shapes_and_types(0);
+ const std::vector* resource =
+ node_context->input_handle_shapes_and_types(0);
if (resource) {
- outer_context->set_output_handle_shapes_and_types(index, *resource);
+ // `ShapesAndType`s contain `ShapeHandle`s. These `ShapeHandle`s point
+ // to `Shape`s that are owned by a different inference context too. We
+ // need to copy them to the outer context to prevent them from being
+ // destroyed before they are used.
+ std::vector copied_shapes_and_types;
+ for (auto& shape_and_type : *resource) {
+ ShapeHandle handle;
+ TensorShapeProto proto;
+ node_context->ShapeHandleToProto(shape_and_type.shape, &proto);
+ TF_RETURN_IF_ERROR(
+ outer_context->MakeShapeFromShapeProto(proto, &handle));
+ copied_shapes_and_types.push_back(
+ ShapeAndType(handle, shape_and_type.dtype, shape_and_type.specialized_type));
+ }
+
+ outer_context->set_output_handle_shapes_and_types(
+ index, copied_shapes_and_types);
}
}
diff --git a/tensorflow/core/data/compression_utils.cc b/tensorflow/core/data/compression_utils.cc
index bbff3a96667d13..40238a05a2614b 100644
--- a/tensorflow/core/data/compression_utils.cc
+++ b/tensorflow/core/data/compression_utils.cc
@@ -29,9 +29,10 @@ Status CompressElement(const std::vector& element,
int64 total_size = 0;
for (auto& component : element) {
if (DataTypeCanUseMemcpy(component.dtype())) {
- // Some datatypes can be memcopied, allowing us to save two copies
- // (AsProtoTensorContent and SerializeToArray).
- total_size += DMAHelper::buffer(&component)->size();
+ const TensorBuffer* buffer = DMAHelper::buffer(&component);
+ if (buffer) {
+ total_size += buffer->size();
+ }
} else {
non_memcpy_components.emplace_back();
component.AsProtoTensorContent(&non_memcpy_components.back());
@@ -53,8 +54,10 @@ Status CompressElement(const std::vector& element,
component.shape().AsProto(metadata->mutable_tensor_shape());
if (DataTypeCanUseMemcpy(component.dtype())) {
const TensorBuffer* buffer = DMAHelper::buffer(&component);
- memcpy(position, buffer->data(), buffer->size());
- metadata->set_tensor_size_bytes(buffer->size());
+ if (buffer) {
+ memcpy(position, buffer->data(), buffer->size());
+ metadata->set_tensor_size_bytes(buffer->size());
+ }
} else {
TensorProto& proto = non_memcpy_components[non_memcpy_component_index++];
proto.SerializeToArray(position, proto.ByteSizeLong());
@@ -94,8 +97,13 @@ Status UncompressElement(const CompressedElement& compressed,
if (DataTypeCanUseMemcpy(metadata.dtype())) {
out->emplace_back(metadata.dtype(), metadata.tensor_shape());
TensorBuffer* buffer = DMAHelper::buffer(&out->back());
- iov[i].iov_base = buffer->data();
- iov[i].iov_len = buffer->size();
+ if (buffer) {
+ iov[i].iov_base = buffer->data();
+ iov[i].iov_len = buffer->size();
+ } else {
+ iov[i].iov_base = nullptr;
+ iov[i].iov_len = 0;
+ }
} else {
// Allocate an empty Tensor. We will fill it out later after
// uncompressing into the tensor_proto_str.
diff --git a/tensorflow/core/framework/BUILD b/tensorflow/core/framework/BUILD
index de44be07c292d2..ba2f759070c177 100644
--- a/tensorflow/core/framework/BUILD
+++ b/tensorflow/core/framework/BUILD
@@ -705,6 +705,8 @@ cc_library(
":tensor_shape",
":types_proto_cc",
"//tensorflow/core/lib/strings:strcat",
+ "//tensorflow/core/platform:macros",
+ "//tensorflow/core/platform:statusor",
"//tensorflow/core/platform:tensor_coding",
"//tensorflow/core/platform:types",
"//tensorflow/core/util:managed_stack_trace",
@@ -795,6 +797,7 @@ tf_cuda_library(
"//tensorflow/core/lib/strings:str_util",
"//tensorflow/core/lib/strings:strcat",
"//tensorflow/core/platform:abi",
+ "//tensorflow/core/platform:errors",
"//tensorflow/core/platform:logging",
"//tensorflow/core/platform:macros",
"//tensorflow/core/platform:platform_port",
diff --git a/tensorflow/core/framework/attr_value_util.cc b/tensorflow/core/framework/attr_value_util.cc
index 76fe36e7f1e2a6..39e3ed888cec5f 100644
--- a/tensorflow/core/framework/attr_value_util.cc
+++ b/tensorflow/core/framework/attr_value_util.cc
@@ -45,7 +45,7 @@ constexpr int kMaxTensorNestDepth = 100;
// not fully defined return -1.
int64 TensorByteSize(const TensorProto& t) {
// num_elements returns -1 if shape is not fully defined.
- int64 num_elems = TensorShape(t.tensor_shape()).num_elements();
+ int64 num_elems = PartialTensorShape(t.tensor_shape()).num_elements();
return num_elems < 0 ? -1 : num_elems * DataTypeSize(t.dtype());
}
diff --git a/tensorflow/core/framework/common_shape_fns.cc b/tensorflow/core/framework/common_shape_fns.cc
index ff527e48c7283c..a7f0740c8e8720 100644
--- a/tensorflow/core/framework/common_shape_fns.cc
+++ b/tensorflow/core/framework/common_shape_fns.cc
@@ -664,6 +664,8 @@ Status Conv2DShapeImpl(shape_inference::InferenceContext* c,
if (c->ValueKnown(input_depth_dim) && c->ValueKnown(filter_input_depth_dim)) {
int64 input_depth_value = c->Value(input_depth_dim),
filter_input_depth_value = c->Value(filter_input_depth_dim);
+ if (filter_input_depth_value == 0)
+ return errors::InvalidArgument("Depth of filter must not be 0");
if (input_depth_value % filter_input_depth_value != 0)
return errors::InvalidArgument(
"Depth of input (", input_depth_value,
@@ -673,6 +675,8 @@ Status Conv2DShapeImpl(shape_inference::InferenceContext* c,
int64 num_groups = input_depth_value / filter_input_depth_value;
if (c->ValueKnown(output_depth_dim)) {
int64 output_depth_value = c->Value(output_depth_dim);
+ if (num_groups == 0)
+ return errors::InvalidArgument("Number of groups must not be 0");
if (output_depth_value % num_groups != 0)
return errors::InvalidArgument(
"Depth of output (", output_depth_value,
@@ -803,6 +807,8 @@ Status Conv3DShape(shape_inference::InferenceContext* c) {
if (c->ValueKnown(input_depth_dim) && c->ValueKnown(filter_input_depth_dim)) {
int64 input_depth_value = c->Value(input_depth_dim),
filter_input_depth_value = c->Value(filter_input_depth_dim);
+ if (filter_input_depth_value == 0)
+ return errors::InvalidArgument("Depth of filter must not be 0");
if (input_depth_value % filter_input_depth_value != 0)
return errors::InvalidArgument(
"Depth of input (", input_depth_value,
@@ -812,6 +818,8 @@ Status Conv3DShape(shape_inference::InferenceContext* c) {
int64 num_groups = input_depth_value / filter_input_depth_value;
if (c->ValueKnown(output_depth_dim)) {
int64 output_depth_value = c->Value(output_depth_dim);
+ if (num_groups == 0)
+ return errors::InvalidArgument("Number of groups must not be 0");
if (output_depth_value % num_groups != 0)
return errors::InvalidArgument(
"Depth of output (", output_depth_value,
@@ -1929,7 +1937,7 @@ Status ConcatShapeHelper(InferenceContext* c, int start_value_index,
}
// Minimum required number of dimensions.
- const int min_rank = concat_dim < 0 ? -concat_dim : concat_dim + 1;
+ const int64 min_rank = concat_dim < 0 ? -concat_dim : concat_dim + 1;
ShapeHandle output_before;
ShapeHandle output_after;
@@ -2424,6 +2432,9 @@ Status SparseReduceShapeFn(InferenceContext* c) {
int64 ndims = shape_vec.size();
absl::flat_hash_set axes;
+ if (ndims == 0)
+ return errors::InvalidArgument(
+ "Number of dims in shape tensor must not be 0");
for (int i = 0; i < axes_vec.size(); i++) {
axes.insert((axes_vec(i) + ndims) % ndims);
}
diff --git a/tensorflow/core/framework/function.cc b/tensorflow/core/framework/function.cc
index b84cfa31157233..ac066da8ba53ad 100644
--- a/tensorflow/core/framework/function.cc
+++ b/tensorflow/core/framework/function.cc
@@ -177,7 +177,9 @@ class FunctionInstantiationHelper {
DataTypeVector dtypes;
TF_RETURN_IF_ERROR(
ArgNumType(attr_values, arg_def, &is_type_list, &dtypes));
- CHECK_GE(dtypes.size(), size_t{1});
+ if (dtypes.size() < size_t{1}) {
+ return errors::Internal("Expected a list of at least one dtype");
+ }
int arg_index = result_.nodes.size();
TF_RETURN_IF_ERROR(
AddItem(arg_def.name(), {true, arg_index, 0, is_type_list, dtypes}));
@@ -185,7 +187,11 @@ class FunctionInstantiationHelper {
for (size_t i = 0; i < dtypes.size(); ++i) {
TF_RETURN_IF_ERROR(AddItem(strings::StrCat(arg_def.name(), ":", i),
{true, arg_index, 0, false, {dtypes[i]}}));
- DCHECK_EQ(arg_index, result_.nodes.size());
+ if (arg_index != result_.nodes.size()) {
+ return errors::Internal(
+ "Expected arg_index to be equal to the number of nodes in result.",
+ " Got ", arg_index, " and ", result_.nodes.size());
+ }
string name = arg_def.name();
if (dtypes.size() > 1) {
strings::StrAppend(&name, "_", i);
diff --git a/tensorflow/core/framework/op_def_util.cc b/tensorflow/core/framework/op_def_util.cc
index 486f92b3b20fdb..8500f247bf0712 100644
--- a/tensorflow/core/framework/op_def_util.cc
+++ b/tensorflow/core/framework/op_def_util.cc
@@ -818,9 +818,10 @@ bool RepeatedAttrDefEqual(
const protobuf::RepeatedPtrField& a2) {
std::unordered_map a1_set;
for (const OpDef::AttrDef& def : a1) {
- DCHECK(a1_set.find(def.name()) == a1_set.end())
- << "AttrDef names must be unique, but '" << def.name()
- << "' appears more than once";
+ if (a1_set.find(def.name()) != a1_set.end()) {
+ LOG(ERROR) << "AttrDef names must be unique, but '" << def.name()
+ << "' appears more than once";
+ }
a1_set[def.name()] = &def;
}
for (const OpDef::AttrDef& def : a2) {
diff --git a/tensorflow/core/framework/resource_handle.cc b/tensorflow/core/framework/resource_handle.cc
index e7f4c2afc90a4a..c8306ca5cf23f9 100644
--- a/tensorflow/core/framework/resource_handle.cc
+++ b/tensorflow/core/framework/resource_handle.cc
@@ -15,14 +15,25 @@ limitations under the License.
#include "tensorflow/core/framework/resource_handle.h"
#include "tensorflow/core/framework/resource_handle.pb.h"
+#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/lib/strings/strcat.h"
+#include "tensorflow/core/platform/errors.h"
+#include "tensorflow/core/platform/macros.h"
namespace tensorflow {
ResourceHandle::ResourceHandle() {}
ResourceHandle::ResourceHandle(const ResourceHandleProto& proto) {
- FromProto(proto);
+ TF_CHECK_OK(FromProto(proto));
+}
+
+Status ResourceHandle::BuildResourceHandle(const ResourceHandleProto& proto,
+ ResourceHandle* out) {
+ if (out == nullptr)
+ return errors::Internal(
+ "BuildResourceHandle() was called with nullptr for the output");
+ return out->FromProto(proto);
}
ResourceHandle::~ResourceHandle() {}
@@ -40,7 +51,7 @@ void ResourceHandle::AsProto(ResourceHandleProto* proto) const {
}
}
-void ResourceHandle::FromProto(const ResourceHandleProto& proto) {
+Status ResourceHandle::FromProto(const ResourceHandleProto& proto) {
set_device(proto.device());
set_container(proto.container());
set_name(proto.name());
@@ -49,10 +60,16 @@ void ResourceHandle::FromProto(const ResourceHandleProto& proto) {
std::vector dtypes_and_shapes;
for (const auto& dtype_and_shape : proto.dtypes_and_shapes()) {
DataType dtype = dtype_and_shape.dtype();
- PartialTensorShape shape(dtype_and_shape.shape());
+ PartialTensorShape shape;
+ Status s = PartialTensorShape::BuildPartialTensorShape(
+ dtype_and_shape.shape(), &shape);
+ if (!s.ok()) {
+ return s;
+ }
dtypes_and_shapes.push_back(DtypeAndPartialTensorShape{dtype, shape});
}
dtypes_and_shapes_ = std::move(dtypes_and_shapes);
+ return Status::OK();
}
string ResourceHandle::SerializeAsString() const {
@@ -63,9 +80,7 @@ string ResourceHandle::SerializeAsString() const {
bool ResourceHandle::ParseFromString(const string& s) {
ResourceHandleProto proto;
- const bool status = proto.ParseFromString(s);
- if (status) FromProto(proto);
- return status;
+ return proto.ParseFromString(s) && FromProto(proto).ok();
}
string ResourceHandle::DebugString() const {
@@ -98,7 +113,9 @@ bool DecodeResourceHandleList(std::unique_ptr d,
if (!proto.ParseFromArray(d->Data(sizes[i]), sizes[i])) {
return false;
}
- ps[i].FromProto(proto);
+ if (!ps[i].FromProto(proto).ok()) {
+ return false;
+ }
}
return true;
}
diff --git a/tensorflow/core/framework/resource_handle.h b/tensorflow/core/framework/resource_handle.h
index 3921d80faf4fe4..cba3b25d4b29f2 100644
--- a/tensorflow/core/framework/resource_handle.h
+++ b/tensorflow/core/framework/resource_handle.h
@@ -38,6 +38,11 @@ class ResourceHandle {
ResourceHandle(const ResourceHandleProto& proto);
~ResourceHandle();
+ // Use this factory method if the `proto` comes from user controlled input, to
+ // prevent a denial of service.
+ static Status BuildResourceHandle(const ResourceHandleProto& proto,
+ ResourceHandle* out);
+
// Unique name for the device containing the resource.
const std::string& device() const { return device_; }
@@ -83,7 +88,7 @@ class ResourceHandle {
// Conversion to and from ResourceHandleProto
void AsProto(ResourceHandleProto* proto) const;
- void FromProto(const ResourceHandleProto& proto);
+ Status FromProto(const ResourceHandleProto& proto);
// Serialization via ResourceHandleProto
std::string SerializeAsString() const;
diff --git a/tensorflow/core/framework/shape_inference.cc b/tensorflow/core/framework/shape_inference.cc
index 721c20b7491aa0..432caaea2792e2 100644
--- a/tensorflow/core/framework/shape_inference.cc
+++ b/tensorflow/core/framework/shape_inference.cc
@@ -14,6 +14,8 @@ limitations under the License.
==============================================================================*/
#include "tensorflow/core/framework/shape_inference.h"
+#include
+
#include "tensorflow/core/framework/bounds_check.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/partial_tensor_shape.h"
@@ -779,6 +781,19 @@ Status InferenceContext::InternalMakeShapeFromTensor(
return ReturnUnknownShape(out);
}
const auto num_dims = Value(shape_dim);
+ // TODO(mihaimaruseac): Should be `TensorShape::MaxDimensions()` as we are
+ // not able to materialize shapes with more than this number of dimensions
+ // but then shape inference would fail for operations such as
+ // `tf.range`/`tf.ones`, etc. where the shape is not really materialized,
+ // only used during the inference. Hence, just prevent doing a `reserve`
+ // with a very large argument.
+ const int64_t max_dimensions = 1 << 25;
+ if (num_dims >= max_dimensions) {
+ return errors::Internal(
+ "Cannot create a tensor with ", num_dims,
+ " dimensions, as these would be more than maximum of ",
+ max_dimensions);
+ }
std::vector dims;
dims.reserve(num_dims);
for (int i = 0; i < num_dims; i++) dims.push_back(UnknownDim());
diff --git a/tensorflow/core/framework/tensor.cc b/tensorflow/core/framework/tensor.cc
index e5eb512a6422a9..9e3190cdab5ad2 100644
--- a/tensorflow/core/framework/tensor.cc
+++ b/tensorflow/core/framework/tensor.cc
@@ -48,6 +48,7 @@ limitations under the License.
#include "tensorflow/core/lib/gtl/inlined_vector.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/lib/strings/strcat.h"
+#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/macros.h"
#include "tensorflow/core/platform/protobuf.h"
@@ -530,6 +531,46 @@ TensorBuffer* FromProtoField(Allocator* a, const TensorProto& in, int64 n) {
return buf;
}
+// Separate implementation for `ResourceHandle` to handle the case when the
+// proto for the resource is invalid. See `resource_handle.h` constructor and
+// static factory builder.
+template <>
+TensorBuffer* FromProtoField(Allocator* a,
+ const TensorProto& in, int64_t n) {
+ CHECK_GT(n, 0);
+ Buffer* buf = new Buffer(a, n);
+ ResourceHandle* data = buf->template base();
+ if (data == nullptr) {
+ buf->Unref();
+ return nullptr;
+ }
+ const int64_t in_n = ProtoHelper::NumElements(in);
+ if (in_n <= 0) {
+ std::fill_n(data, n, ResourceHandle());
+ } else {
+ // If tensor shape says we have n < in_n elements in the output tensor
+ // then make sure to only decode the first n out of the in_n elements in the
+ // in tensors. In all other cases, we decode all in_n elements of in and set
+ // the remaining elements up to n to be the default ResourceHandle() value.
+ const int64_t real_n = n < in_n ? n : in_n;
+ for (int64_t i = 0; i < real_n; ++i) {
+ Status s = ResourceHandle::BuildResourceHandle(in.resource_handle_val(i),
+ &data[i]);
+ if (!s.ok()) {
+ LOG(ERROR) << "Could not decode resource handle from proto \""
+ << in.resource_handle_val(i).ShortDebugString()
+ << "\", returned status: " << s.ToString();
+ buf->Unref();
+ return nullptr;
+ }
+ }
+ for (int64_t i = in_n; i < n; ++i) {
+ data[i] = ResourceHandle();
+ }
+ }
+ return buf;
+}
+
template <>
TensorBuffer* FromProtoField(Allocator* a, const TensorProto& in,
int64 n) {
@@ -717,11 +758,11 @@ bool Tensor::RefCountIsOne() const {
// The macro CASES() expands to a switch statement conditioned on
// TYPE_ENUM. Each case expands the STMTS after a typedef for T.
#define SINGLE_ARG(...) __VA_ARGS__
-#define CASE(TYPE, STMTS) \
- case DataTypeToEnum::value: { \
- typedef TYPE T; \
- STMTS; \
- break; \
+#define CASE(TYPE, STMTS) \
+ case DataTypeToEnum::value: { \
+ typedef TF_ATTRIBUTE_UNUSED TYPE T; \
+ STMTS; \
+ break; \
}
#define CASES_WITH_DEFAULT(TYPE_ENUM, STMTS, INVALID, DEFAULT) \
switch (TYPE_ENUM) { \
@@ -757,9 +798,8 @@ bool Tensor::RefCountIsOne() const {
}
#define CASES(TYPE_ENUM, STMTS) \
- CASES_WITH_DEFAULT(TYPE_ENUM, STMTS, \
- LOG(FATAL) << "Unexpected type: " << TYPE_ENUM; \
- , LOG(FATAL) << "Type not set";)
+ CASES_WITH_DEFAULT(TYPE_ENUM, STMTS, LOG(FATAL) << "Type not set"; \
+ , LOG(FATAL) << "Unexpected type: " << TYPE_ENUM;)
Tensor::Tensor(Allocator* a, DataType type, const TensorShape& shape)
: shape_(shape), buf_(nullptr) {
@@ -789,6 +829,16 @@ Tensor::Tensor(Allocator* a, DataType type, const TensorShape& shape,
}
}
+Status Tensor::BuildTensor(DataType type, const TensorShape& shape,
+ Tensor* out_tensor) {
+ // Avoid crashes due to invalid or unsupported types.
+ CASES_WITH_DEFAULT(
+ type, {}, return errors::InvalidArgument("Type not set"),
+ return errors::InvalidArgument("Unexpected type: ", DataType_Name(type)));
+ *out_tensor = Tensor(type, shape);
+ return Status::OK();
+}
+
// NOTE(mrry): The default allocator for a Tensor (when none is specified) is
// the default CPU allocator for NUMA zone 0. Accessing that currently involves
// acquiring a lock, which guards initialization of the per-NUMA zone
@@ -927,6 +977,15 @@ bool Tensor::FromProto(Allocator* a, const TensorProto& proto) {
dtype_error = true, dtype_error = true);
}
if (dtype_error || p == nullptr) return false;
+ } else {
+ // Handle the case of empty tensors (N = 0) or tensors with incomplete shape
+ // (N = -1). All other values of `shape.num_elements()` should be invalid by
+ // construction.
+ // Here, we just need to validate that the `proto.dtype()` value is valid.
+ bool dtype_error = false;
+ CASES_WITH_DEFAULT(proto.dtype(), break, dtype_error = true,
+ dtype_error = true);
+ if (dtype_error) return false;
}
shape_ = shape;
set_dtype(proto.dtype());
diff --git a/tensorflow/core/framework/tensor.h b/tensorflow/core/framework/tensor.h
index 33a240d85dc5c9..dd01bfc272010a 100644
--- a/tensorflow/core/framework/tensor.h
+++ b/tensorflow/core/framework/tensor.h
@@ -170,6 +170,15 @@ class Tensor {
/// for details.
explicit Tensor(DataType type);
+ /// \brief Initializes a tensor with the input `type` and `shape`, or returns
+ /// an error and leaves `out_tensor` unmodified. This factory method should be
+ /// used instead of the corresponding constructor if calling code cannot
+ /// validate that the `DataType` is valid and supported.
+ ///
+ /// The underlying buffer is allocated using a `CPUAllocator`.
+ static Status BuildTensor(DataType type, const TensorShape& shape,
+ Tensor* out_tensor);
+
private:
// A tag type for selecting the `Tensor` constructor overload that creates a
// scalar tensor in host memory.
diff --git a/tensorflow/core/framework/tensor_shape.cc b/tensorflow/core/framework/tensor_shape.cc
index 5144577e7aa0f5..117a70b7fa39a4 100644
--- a/tensorflow/core/framework/tensor_shape.cc
+++ b/tensorflow/core/framework/tensor_shape.cc
@@ -229,7 +229,7 @@ Status TensorShapeBase::InitDims(gtl::ArraySlice dim_sizes) {
if (!kIsPartial && !large_size) {
for (auto s : dim_sizes) {
if (TF_PREDICT_FALSE(s < 0)) {
- return errors::Internal(
+ return errors::InvalidArgument(
"Expected shape dimensions to be non-negative, got ", s);
}
}
@@ -411,7 +411,8 @@ template
Status TensorShapeBase::AddDimWithStatus(int64 size) {
if (!kIsPartial) {
if (TF_PREDICT_FALSE(size < 0)) {
- return errors::Internal("Expected a non-negative size, got ", size);
+ return errors::InvalidArgument("Expected a non-negative size, got ",
+ size);
}
}
@@ -420,7 +421,7 @@ Status TensorShapeBase::AddDimWithStatus(int64 size) {
}
if (TF_PREDICT_FALSE(ndims_byte() >= MaxDimensions())) {
- return errors::Internal("Too many dimensions in tensor");
+ return errors::InvalidArgument("Too many dimensions in tensor");
}
int64 new_num_elements;
@@ -429,9 +430,9 @@ Status TensorShapeBase::AddDimWithStatus(int64 size) {
} else {
new_num_elements = MultiplyWithoutOverflow(num_elements(), size);
if (TF_PREDICT_FALSE(new_num_elements < 0)) {
- return errors::Internal("Encountered overflow when multiplying ",
- num_elements(), " with ", size,
- ", result: ", new_num_elements);
+ return errors::InvalidArgument("Encountered overflow when multiplying ",
+ num_elements(), " with ", size,
+ ", result: ", new_num_elements);
}
}
@@ -521,7 +522,8 @@ template
Status TensorShapeBase::InsertDimWithStatus(int d, int64 size) {
if (!kIsPartial) {
if (TF_PREDICT_FALSE(size < 0)) {
- return errors::Internal("Expected a non-negative size, got ", size);
+ return errors::InvalidArgument("Expected a non-negative size, got ",
+ size);
}
}
@@ -591,13 +593,14 @@ void TensorShapeBase::set_dim(int d, int64 size) {
template
Status TensorShapeBase::SetDimWithStatus(int d, int64 size) {
if (TF_PREDICT_FALSE(d < 0)) {
- return errors::Internal("Index must be non-negative, got ", d);
+ return errors::InvalidArgument("Index must be non-negative, got ", d);
}
if (TF_PREDICT_FALSE(d >= dims())) {
- return errors::Internal("Index must be less than ", dims(), ", got ", d);
+ return errors::InvalidArgument("Index must be less than ", dims(), ", got ",
+ d);
}
- if (TF_PREDICT_FALSE(size < 0)) {
- return errors::Internal("Expected a non-negative size, got ", size);
+ if (TF_PREDICT_FALSE(!kIsPartial && size < 0)) {
+ return errors::InvalidArgument("Expected a non-negative size, got ", size);
}
if (tag() == REP16 && size < kMaxRep16) {
diff --git a/tensorflow/core/framework/tensor_shape.h b/tensorflow/core/framework/tensor_shape.h
index a690123f0ceaf9..d12994304faf13 100644
--- a/tensorflow/core/framework/tensor_shape.h
+++ b/tensorflow/core/framework/tensor_shape.h
@@ -359,6 +359,23 @@ class TensorShape : public TensorShapeBase {
public:
using TensorShapeBase::TensorShapeBase;
+ // These factory methods should be used instead of the constructors that take
+ // an array of sizes if calling code cannot validate that the sizes specify a
+ // valid `TensorShape`.
+ // The value in `*out` is valid iff the returned value is `Status::OK`.
+ static Status BuildTensorShape(gtl::ArraySlice dim_sizes,
+ TensorShape* out) {
+ return BuildTensorShapeBase(dim_sizes, out);
+ }
+ static Status BuildTensorShape(std::initializer_list dim_sizes,
+ TensorShape* out) {
+ return BuildTensorShape(gtl::ArraySlice(dim_sizes), out);
+ }
+ static Status BuildTensorShape(const TensorShapeProto& proto,
+ TensorShape* out) {
+ return BuildTensorShapeBase(proto, out);
+ }
+
/// Allow a TensorShape to be used as a PartialTensorShape without copying
operator const PartialTensorShape&() const; // NOLINT(runtime/explicit)
@@ -508,6 +525,23 @@ class PartialTensorShape : public TensorShapeBase {
PartialTensorShape() {}
using TensorShapeBase::TensorShapeBase;
+ // These factory methods should be used instead of the constructors that take
+ // an array of sizes if calling code cannot validate that the sizes specify a
+ // valid `PartialTensorShape`.
+ // The value in `*out` is valid iff the returned value is `Status::OK`.
+ static Status BuildPartialTensorShape(gtl::ArraySlice dim_sizes,
+ PartialTensorShape* out) {
+ return BuildTensorShapeBase(dim_sizes, out);
+ }
+ static Status BuildPartialTensorShape(
+ std::initializer_list dim_sizes, PartialTensorShape* out) {
+ return BuildPartialTensorShape(gtl::ArraySlice(dim_sizes), out);
+ }
+ static Status BuildPartialTensorShape(const TensorShapeProto& proto,
+ PartialTensorShape* out) {
+ return BuildTensorShapeBase(proto, out);
+ }
+
/// Add a dimension to the end ("inner-most"), returns a new
/// PartialTensorShape.
/// REQUIRES: `size >= -1`, where -1 means unknown
diff --git a/tensorflow/core/framework/tensor_shape_test.cc b/tensorflow/core/framework/tensor_shape_test.cc
index f41d00f2a46472..cf087d0647f662 100644
--- a/tensorflow/core/framework/tensor_shape_test.cc
+++ b/tensorflow/core/framework/tensor_shape_test.cc
@@ -214,7 +214,7 @@ TEST(TensorShapeTest, AddDimWithStatus) {
ASSERT_EQ(4, s.dims());
status = s.AddDimWithStatus(-1);
- EXPECT_EQ(tensorflow::error::INTERNAL, status.code());
+ EXPECT_EQ(tensorflow::error::INVALID_ARGUMENT, status.code());
}
TEST(TensorShapeTest, Factory) {
@@ -225,7 +225,7 @@ TEST(TensorShapeTest, Factory) {
ASSERT_EQ(3, s.dims());
status = TensorShape::BuildTensorShapeBase({-10, 5, 20}, &s);
- EXPECT_EQ(tensorflow::error::INTERNAL, status.code());
+ EXPECT_EQ(tensorflow::error::INVALID_ARGUMENT, status.code());
}
// -----------------------------------------------------------------------
diff --git a/tensorflow/core/framework/tensor_slice.cc b/tensorflow/core/framework/tensor_slice.cc
index 975e1e2e24a439..7041b011157434 100644
--- a/tensorflow/core/framework/tensor_slice.cc
+++ b/tensorflow/core/framework/tensor_slice.cc
@@ -14,7 +14,10 @@ limitations under the License.
==============================================================================*/
#include "tensorflow/core/framework/tensor_slice.h"
+
+#include
#include
+
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/strings/numbers.h"
#include "tensorflow/core/lib/strings/str_util.h"
@@ -44,6 +47,34 @@ TensorSlice::TensorSlice(
}
}
+Status TensorSlice::BuildTensorSlice(const TensorSliceProto& proto,
+ TensorSlice* output) {
+ output->Clear();
+ output->starts_.reserve(proto.extent_size());
+ output->lengths_.reserve(proto.extent_size());
+ for (const auto& e : proto.extent()) {
+ int64_t l = GetExtentLength(e);
+ if (e.start() != 0 || l != kFullExtent) {
+ if (e.start() < 0 || l <= 0) {
+ return errors::InvalidArgument(
+ "Expected non-negative start and positive length but got start = ",
+ e.start(), ", length = ", l, ": extent = ", e.ShortDebugString());
+ }
+ // Calculating the extent end must not cause signed integer overflow.
+ if (static_cast(e.start()) + static_cast(e.length()) >
+ std::numeric_limits::max()) {
+ return errors::InvalidArgument(
+ "Extent end exceeds the maximum possible size: extent = ",
+ e.ShortDebugString());
+ }
+ }
+ output->starts_.push_back(e.start());
+ output->lengths_.push_back(l);
+ }
+
+ return Status::OK();
+}
+
Status TensorSlice::Parse(const string& str, TensorSlice* slice) {
std::vector items = str_util::Split(str, ':', str_util::SkipEmpty());
slice->starts_.reserve(items.size());
diff --git a/tensorflow/core/framework/tensor_slice.h b/tensorflow/core/framework/tensor_slice.h
index 82f21fb17eec78..4c2795694564da 100644
--- a/tensorflow/core/framework/tensor_slice.h
+++ b/tensorflow/core/framework/tensor_slice.h
@@ -47,6 +47,12 @@ class TensorSlice {
explicit TensorSlice(const TensorSliceProto& proto);
explicit TensorSlice(std::initializer_list> extents);
+ // This factory methods should be used instead of the constructor that takes a
+ // `TensorSliceProto` if calling code cannot validate that the sizes specify a
+ // valid `TensorSlice`.
+ static Status BuildTensorSlice(const TensorSliceProto& proto,
+ TensorSlice* output);
+
static Status Parse(const string& str, TensorSlice* output);
static TensorSlice ParseOrDie(const string& str) {
TensorSlice ret;
diff --git a/tensorflow/core/framework/tensor_slice_test.cc b/tensorflow/core/framework/tensor_slice_test.cc
index 54e680484e228b..69b7c7cd084e33 100644
--- a/tensorflow/core/framework/tensor_slice_test.cc
+++ b/tensorflow/core/framework/tensor_slice_test.cc
@@ -15,6 +15,8 @@ limitations under the License.
#include "tensorflow/core/framework/tensor_slice.h"
+#include
+
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/protobuf.h"
@@ -123,6 +125,48 @@ TEST(TensorSliceTest, Serialization) {
}
}
+// Testing `BuildTensorSlice` with valid and invalid input protos.
+TEST(TensorSliceTest, BuildTensorSlice) {
+ TensorSliceProto proto;
+ TensorSlice({{0, -1}, {0, 10}, {14, 1}}).AsProto(&proto);
+ TensorSlice s;
+
+ // Successful building.
+ {
+ TF_ASSERT_OK(TensorSlice::BuildTensorSlice(proto, &s));
+ EXPECT_EQ("-:0,10:14,1", s.DebugString());
+ }
+
+ // Failed building due to negative extent start.
+ {
+ TensorSliceProto invalid_proto = proto;
+ invalid_proto.mutable_extent(0)->set_start(-1);
+ EXPECT_FALSE(TensorSlice::BuildTensorSlice(invalid_proto, &s).ok());
+ }
+
+ // Failed building due to negative extent length.
+ {
+ TensorSliceProto invalid_proto = proto;
+ invalid_proto.mutable_extent(2)->set_length(-1);
+ EXPECT_FALSE(TensorSlice::BuildTensorSlice(invalid_proto, &s).ok());
+ }
+
+ // Failed building due to missing extent length.
+ {
+ TensorSliceProto invalid_proto = proto;
+ invalid_proto.mutable_extent(2)->clear_length();
+ EXPECT_FALSE(TensorSlice::BuildTensorSlice(invalid_proto, &s).ok());
+ }
+
+ // Failed building due to extent end overflowing.
+ {
+ TensorSliceProto invalid_proto = proto;
+ invalid_proto.mutable_extent(2)->set_length(
+ std::numeric_limits::max());
+ EXPECT_FALSE(TensorSlice::BuildTensorSlice(invalid_proto, &s).ok());
+ }
+}
+
// Testing the slice intersection
TEST(TensorSliceTest, Intersection) {
// "EVERYTHING" intersects with everything
diff --git a/tensorflow/core/grappler/costs/BUILD b/tensorflow/core/grappler/costs/BUILD
index 9204607f3838e8..80a6648cd5b2cf 100644
--- a/tensorflow/core/grappler/costs/BUILD
+++ b/tensorflow/core/grappler/costs/BUILD
@@ -182,6 +182,7 @@ tf_cuda_library(
"//tensorflow/core:lib_proto_parsing",
"//tensorflow/core:protos_all_cc",
"//tensorflow/core/grappler:utils",
+ "//tensorflow/core/util:overflow",
"//tensorflow/core/grappler/clusters:utils",
] + tf_protos_grappler(),
)
@@ -338,22 +339,11 @@ cc_library(
"//tensorflow/core:lib",
"//tensorflow/core:protos_all_cc",
"//tensorflow/core/grappler/clusters:utils",
+ "//tensorflow/core/util:overflow",
+ "//tensorflow/core/platform:statusor",
] + tf_protos_grappler(),
)
-tf_cc_test(
- name = "op_level_cost_estimator_test",
- srcs = ["op_level_cost_estimator_test.cc"],
- tags = ["no_oss"], # b/163222310
- deps = [
- ":op_level_cost_estimator",
- "//tensorflow/core:framework",
- "//tensorflow/core:protos_all_cc",
- "//tensorflow/core:test",
- "//tensorflow/core:test_main",
- ],
-)
-
cc_library(
name = "analytical_cost_estimator",
srcs = ["analytical_cost_estimator.cc"],
diff --git a/tensorflow/core/grappler/costs/graph_properties.cc b/tensorflow/core/grappler/costs/graph_properties.cc
index 644efe3326ab9f..441a7524bb4eda 100644
--- a/tensorflow/core/grappler/costs/graph_properties.cc
+++ b/tensorflow/core/grappler/costs/graph_properties.cc
@@ -1128,7 +1128,12 @@ class SymbolicShapeRefiner {
GetUnknownOutputShape(node, output_port);
InferenceContext* ctx = GetContext(node);
if (ctx == nullptr) {
- return errors::InvalidArgument("Missing context");
+ return errors::InvalidArgument("SetUnknownShape: Missing context");
+ }
+ if (output_port < 0 || output_port >= ctx->num_outputs()) {
+ return errors::InvalidArgument(
+ "SetUnknownShape: output_port must be in [0, ", ctx->num_outputs(),
+ ") but was ", output_port);
}
ctx->set_output(output_port, shape);
return Status::OK();
diff --git a/tensorflow/core/grappler/costs/op_level_cost_estimator.cc b/tensorflow/core/grappler/costs/op_level_cost_estimator.cc
index 009f2471d39fd5..ae6bc399aec544 100644
--- a/tensorflow/core/grappler/costs/op_level_cost_estimator.cc
+++ b/tensorflow/core/grappler/costs/op_level_cost_estimator.cc
@@ -27,6 +27,7 @@ limitations under the License.
#include "tensorflow/core/grappler/costs/op_context.h"
#include "tensorflow/core/grappler/costs/utils.h"
#include "tensorflow/core/platform/errors.h"
+#include "tensorflow/core/util/overflow.h"
namespace tensorflow {
namespace grappler {
@@ -1535,7 +1536,14 @@ int64 OpLevelCostEstimator::CalculateTensorElementCount(
auto tensor_shape =
MaybeGetMinimumShape(tensor.shape(), num_dims, found_unknown_shapes);
for (const auto& dim : tensor_shape.dim()) {
- tensor_size *= dim.size();
+ int64_t new_tensor_size = MultiplyWithoutOverflow(tensor_size, dim.size());
+ if (new_tensor_size < 0) {
+ VLOG(1) << "Overflow encountered when computing element count of a "
+ "tensor, multiplying "
+ << tensor_size << " with " << dim.size();
+ return -1;
+ }
+ tensor_size = new_tensor_size;
}
return tensor_size;
}
@@ -1545,7 +1553,13 @@ int64 OpLevelCostEstimator::CalculateTensorSize(
int64 count = CalculateTensorElementCount(tensor, found_unknown_shapes);
int size = DataTypeSize(BaseType(tensor.dtype()));
VLOG(2) << "Count: " << count << " DataTypeSize: " << size;
- return count * size;
+ int64_t tensor_size = MultiplyWithoutOverflow(count, size);
+ if (tensor_size < 0) {
+ VLOG(1) << "Overflow encountered when computing tensor size, multiplying "
+ << count << " with " << size;
+ return -1;
+ }
+ return tensor_size;
}
int64 OpLevelCostEstimator::CalculateInputSize(const OpInfo& op_info,
@@ -1598,7 +1612,14 @@ int64 OpLevelCostEstimator::CalculateOutputSize(const OpInfo& op_info,
auto output_shape = MaybeGetMinimumShape(original_output_shape, num_dims,
found_unknown_shapes);
for (const auto& dim : output_shape.dim()) {
- output_size *= dim.size();
+ int64_t new_output_size =
+ MultiplyWithoutOverflow(output_size, dim.size());
+ if (new_output_size < 0) {
+ VLOG(1) << "Overflow encountered when estimating cost, multiplying "
+ << output_size << " with " << dim.size();
+ return -1;
+ }
+ output_size = new_output_size;
}
total_output_size += output_size;
VLOG(1) << "Output Size: " << output_size
@@ -2121,7 +2142,7 @@ OpInfo::TensorProperties OpLevelCostEstimator::DescribeTensor(
}
/* static */
-OpLevelCostEstimator::ConvolutionDimensions
+StatusOr
OpLevelCostEstimator::OpDimensionsFromInputs(
const TensorShapeProto& original_image_shape, const OpInfo& op_info,
bool* found_unknown_shapes) {
@@ -2158,6 +2179,11 @@ OpLevelCostEstimator::OpDimensionsFromInputs(
std::vector strides = GetStrides(op_info);
int64 sx = strides[x_index];
int64 sy = strides[y_index];
+ if (sx == 0 || sy == 0) {
+ return errors::InvalidArgument(
+ "Stride must be > 0 for Height and Width, but got (", sy, ", ", sx,
+ ")");
+ }
const auto padding = GetPadding(op_info);
int64 ox = GetOutputSize(ix, kx, sx, padding);
@@ -2174,8 +2200,9 @@ Status OpLevelCostEstimator::PredictMaxPool(const OpContext& op_context,
bool found_unknown_shapes = false;
const auto& op_info = op_context.op_info;
// x: op_info.inputs(0)
- ConvolutionDimensions dims = OpDimensionsFromInputs(
- op_info.inputs(0).shape(), op_info, &found_unknown_shapes);
+ TF_ASSIGN_OR_RETURN(ConvolutionDimensions dims,
+ OpDimensionsFromInputs(op_info.inputs(0).shape(), op_info,
+ &found_unknown_shapes));
// kx * ky - 1 comparisons per output (kx * xy > 1)
// or 1 copy per output (kx * k1 = 1).
int per_output_ops = dims.kx * dims.ky == 1 ? 1 : dims.kx * dims.ky - 1;
@@ -2215,8 +2242,9 @@ Status OpLevelCostEstimator::PredictMaxPoolGrad(const OpContext& op_context,
op_info.ShortDebugString());
}
- ConvolutionDimensions dims = OpDimensionsFromInputs(
- op_info.inputs(0).shape(), op_info, &found_unknown_shapes);
+ TF_ASSIGN_OR_RETURN(ConvolutionDimensions dims,
+ OpDimensionsFromInputs(op_info.inputs(0).shape(), op_info,
+ &found_unknown_shapes));
int64 ops = 0;
if (dims.kx == 1 && dims.ky == 1) {
@@ -2291,8 +2319,9 @@ Status OpLevelCostEstimator::PredictAvgPool(const OpContext& op_context,
bool found_unknown_shapes = false;
const auto& op_info = op_context.op_info;
// x: op_info.inputs(0)
- ConvolutionDimensions dims = OpDimensionsFromInputs(
- op_info.inputs(0).shape(), op_info, &found_unknown_shapes);
+ TF_ASSIGN_OR_RETURN(ConvolutionDimensions dims,
+ OpDimensionsFromInputs(op_info.inputs(0).shape(), op_info,
+ &found_unknown_shapes));
// kx * ky - 1 additions and 1 multiplication per output.
int64 ops = dims.batch * dims.ox * dims.oy * dims.oz * dims.kx * dims.ky;
@@ -2348,8 +2377,9 @@ Status OpLevelCostEstimator::PredictAvgPoolGrad(const OpContext& op_context,
found_unknown_shapes = true;
}
- ConvolutionDimensions dims =
- OpDimensionsFromInputs(x_shape, op_info, &found_unknown_shapes);
+ TF_ASSIGN_OR_RETURN(
+ ConvolutionDimensions dims,
+ OpDimensionsFromInputs(x_shape, op_info, &found_unknown_shapes));
int64 ops = 0;
if (dims.kx <= dims.sx && dims.ky <= dims.sy) {
@@ -2375,8 +2405,9 @@ Status OpLevelCostEstimator::PredictFusedBatchNorm(
// offset: op_info.inputs(2)
// mean: op_info.inputs(3) --> only for inference
// variance: op_info.inputs(4) --> only for inference
- ConvolutionDimensions dims = OpDimensionsFromInputs(
- op_info.inputs(0).shape(), op_info, &found_unknown_shapes);
+ TF_ASSIGN_OR_RETURN(ConvolutionDimensions dims,
+ OpDimensionsFromInputs(op_info.inputs(0).shape(), op_info,
+ &found_unknown_shapes));
const bool is_training = IsTraining(op_info);
int64 ops = 0;
@@ -2425,8 +2456,9 @@ Status OpLevelCostEstimator::PredictFusedBatchNormGrad(
// scale: op_info.inputs(2)
// mean: op_info.inputs(3)
// variance or inverse of variance: op_info.inputs(4)
- ConvolutionDimensions dims = OpDimensionsFromInputs(
- op_info.inputs(1).shape(), op_info, &found_unknown_shapes);
+ TF_ASSIGN_OR_RETURN(ConvolutionDimensions dims,
+ OpDimensionsFromInputs(op_info.inputs(1).shape(), op_info,
+ &found_unknown_shapes));
int64 ops = 0;
const auto rsqrt_cost = Eigen::internal::functor_traits<
@@ -2646,27 +2678,42 @@ Status OpLevelCostEstimator::PredictCropAndResize(const OpContext& op_context,
// calculation differs from rough estimate in implementation, as it separates
// out cost per box from cost per pixel and cost per element.
+ // Since crop arguments are user controlled, check for overflow.
+ int64_t crop_area = MultiplyWithoutOverflow(crop_height, crop_width);
+ if (crop_area < 0)
+ return errors::InvalidArgument("Cannot estimate cost, multiplying ",
+ crop_height, " with ", crop_width,
+ " would overflow");
+ int64_t crop_volume = MultiplyWithoutOverflow(crop_area, num_boxes);
+ if (crop_volume < 0)
+ return errors::InvalidArgument("Cannot estimate cost, multiplying ",
+ crop_area, " with ", num_boxes,
+ " would overflow");
+ int64_t crop_depth = MultiplyWithoutOverflow(crop_height, num_boxes);
+ if (crop_depth < 0)
+ return errors::InvalidArgument("Cannot estimate cost, multiplying ",
+ crop_height, " with ", num_boxes,
+ " would overflow");
+
// Ops for variables height_scale and width_scale.
int64 ops = (sub_cost * 6 + mul_cost * 2 + div_cost * 2) * num_boxes;
// Ops for variable in_y.
- ops += (mul_cost * 2 + sub_cost + add_cost) * crop_height * num_boxes;
+ ops += (mul_cost * 2 + sub_cost + add_cost) * crop_depth;
// Ops for variable in_x (same computation across both branches).
- ops += (mul_cost * 2 + sub_cost + add_cost) * crop_height * crop_width *
- num_boxes;
+ ops += (mul_cost * 2 + sub_cost + add_cost) * crop_volume;
// Specify op_cost based on the method.
if (use_bilinear_interp) {
// Ops for variables top_y_index, bottom_y_index, y_lerp.
- ops += (floor_cost + ceil_cost + sub_cost) * crop_height * num_boxes;
+ ops += (floor_cost + ceil_cost + sub_cost) * crop_depth;
// Ops for variables left_x, right_x, x_lerp;
- ops += (floor_cost + ceil_cost + sub_cost) * crop_height * crop_width *
- num_boxes;
+ ops += (floor_cost + ceil_cost + sub_cost) * crop_volume;
// Ops for innermost loop across depth.
ops +=
(cast_to_float_cost * 4 + add_cost * 3 + sub_cost * 3 + mul_cost * 3) *
output_elements;
} else /* method == "nearest" */ {
// Ops for variables closest_x_index and closest_y_index.
- ops += round_cost * 2 * crop_height * crop_width * num_boxes;
+ ops += round_cost * 2 * crop_volume;
// Ops for innermost loop across depth.
ops += cast_to_float_cost * output_elements;
}
diff --git a/tensorflow/core/grappler/costs/op_level_cost_estimator.h b/tensorflow/core/grappler/costs/op_level_cost_estimator.h
index 54382927f7b904..3148de33fa9ba5 100644
--- a/tensorflow/core/grappler/costs/op_level_cost_estimator.h
+++ b/tensorflow/core/grappler/costs/op_level_cost_estimator.h
@@ -22,6 +22,7 @@ limitations under the License.
#include "tensorflow/core/grappler/costs/op_context.h"
#include "tensorflow/core/grappler/costs/op_performance_data.pb.h"
#include "tensorflow/core/lib/core/status.h"
+#include "tensorflow/core/platform/statusor.h"
#include "tensorflow/core/util/padding.h"
namespace tensorflow {
@@ -290,7 +291,7 @@ class OpLevelCostEstimator {
bool* found_unknown_shapes);
// For Pooling, FusedBatchNorm, and their grad ops.
- static ConvolutionDimensions OpDimensionsFromInputs(
+ static StatusOr OpDimensionsFromInputs(
const TensorShapeProto& original_image_shape, const OpInfo& op_info,
bool* found_unknown_shapes);
diff --git a/tensorflow/core/grappler/costs/op_level_cost_estimator_test.cc b/tensorflow/core/grappler/costs/op_level_cost_estimator_test.cc
index 23373d3dc1b629..eda84ec3276001 100644
--- a/tensorflow/core/grappler/costs/op_level_cost_estimator_test.cc
+++ b/tensorflow/core/grappler/costs/op_level_cost_estimator_test.cc
@@ -24,6 +24,7 @@ limitations under the License.
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/framework/types.h"
+#include "tensorflow/core/platform/status_matchers.h"
#include "tensorflow/core/platform/test.h"
#include "tensorflow/core/protobuf/device_properties.pb.h"
@@ -558,9 +559,10 @@ class OpLevelCostEstimatorTest : public ::testing::Test {
}
bool found_unknown_shapes;
- auto dims = OpLevelCostEstimator::OpDimensionsFromInputs(
- op_context.op_info.inputs(0).shape(), op_context.op_info,
- &found_unknown_shapes);
+ TF_ASSERT_OK_AND_ASSIGN(
+ auto dims, OpLevelCostEstimator::OpDimensionsFromInputs(
+ op_context.op_info.inputs(0).shape(), op_context.op_info,
+ &found_unknown_shapes));
Padding padding_enum;
if (padding == "VALID") {
padding_enum = Padding::VALID;
@@ -581,6 +583,38 @@ class OpLevelCostEstimatorTest : public ::testing::Test {
EXPECT_EQ(padding_enum, dims.padding);
}
+ StatusOr
+ CallOpDimensionsFromInputs(const int n, const int h, const int w, const int c,
+ const int kx, const int ky, const int sx,
+ const int sy, const string& data_format,
+ const string& padding) {
+ OpContext op_context;
+
+ const std::vector x = {n, h, w, c};
+ const std::vector ksize = {1, kx, ky, 1};
+ std::vector strides;
+ if (data_format == "NHWC") {
+ strides = {1, sy, sx, 1};
+ } else {
+ strides = {1, 1, sy, sx};
+ }
+
+ auto& op_info = op_context.op_info;
+ SetCpuDevice(&op_info);
+ op_info.set_op("MaxPool");
+
+ DescribeTensor4D(x[0], x[1], x[2], x[3], op_info.add_inputs());
+ auto* attr = op_info.mutable_attr();
+ SetAttrValue(data_format, &(*attr)["data_format"]);
+ SetAttrValue(padding, &(*attr)["padding"]);
+ SetAttrValue(strides, &(*attr)["strides"]);
+ SetAttrValue(ksize, &(*attr)["ksize"]);
+ bool found_unknown_shapes;
+ return OpLevelCostEstimator::OpDimensionsFromInputs(
+ op_context.op_info.inputs(0).shape(), op_context.op_info,
+ &found_unknown_shapes);
+ }
+
OpLevelCostEstimator estimator_;
};
@@ -1383,6 +1417,26 @@ TEST_F(OpLevelCostEstimatorTest, OpDimensionsFromInputs) {
}
}
+TEST_F(OpLevelCostEstimatorTest, OpDimensionsFromInputsError) {
+ std::vector paddings = {"VALID", "SAME"};
+ std::vector formats = {"NHWC", "NCHW"};
+ for (const auto& p : paddings) {
+ for (const auto& f : formats) {
+ // n, h, w, c, kx, ky, sx, sy, data_format, padding.
+ ASSERT_THAT(
+ CallOpDimensionsFromInputs(10, 14, 14, 3840, 3, 3, 0, 2, f, p),
+ testing::StatusIs(
+ error::INVALID_ARGUMENT,
+ "Stride must be > 0 for Height and Width, but got (2, 0)"));
+ ASSERT_THAT(
+ CallOpDimensionsFromInputs(10, 14, 14, 3840, 3, 3, 2, 0, f, p),
+ testing::StatusIs(
+ error::INVALID_ARGUMENT,
+ "Stride must be > 0 for Height and Width, but got (0, 2)"));
+ }
+ }
+}
+
TEST_F(OpLevelCostEstimatorTest, PredictMaxPool) {
auto predict_max_pool = [this](const int n, const int in, const int c,
const int k, const int s,
diff --git a/tensorflow/core/grappler/costs/utils.cc b/tensorflow/core/grappler/costs/utils.cc
index c6bc7555d3d1a3..d48695c0793362 100644
--- a/tensorflow/core/grappler/costs/utils.cc
+++ b/tensorflow/core/grappler/costs/utils.cc
@@ -45,6 +45,7 @@ limitations under the License.
#include "tensorflow/core/platform/protobuf.h"
#include "tensorflow/core/protobuf/config.pb.h"
#include "tensorflow/core/util/device_name_utils.h"
+#include "tensorflow/core/util/overflow.h"
namespace tensorflow {
namespace grappler {
@@ -217,7 +218,13 @@ int64 CalculateTensorSize(const OpInfo::TensorProperties& prop) {
}
int64 num_elems = TensorShape(shape).num_elements();
- return num_elems * size;
+ int64 tensor_size = MultiplyWithoutOverflow(num_elems, size);
+ if (tensor_size < 0) {
+ VLOG(1) << "Overflow encountered when computing tensor size, multiplying "
+ << num_elems << " with " << size;
+ return -1;
+ }
+ return tensor_size;
}
int64 CalculateOutputSize(
diff --git a/tensorflow/core/grappler/costs/utils_test.cc b/tensorflow/core/grappler/costs/utils_test.cc
index db5c11f0fe102d..6f6d3b2a14b0d9 100644
--- a/tensorflow/core/grappler/costs/utils_test.cc
+++ b/tensorflow/core/grappler/costs/utils_test.cc
@@ -202,6 +202,10 @@ TEST(UtilsTest, CalculateTensorSize) {
EXPECT_EQ(
DataTypeSize(DT_FLOAT) * 1 * 7 * 1 * 99,
CalculateTensorSize(ShapeToTensorProperty({-1, 7, -1, 99}, DT_FLOAT)));
+
+ // Test overflow
+ EXPECT_EQ(-1, CalculateTensorSize(ShapeToTensorProperty(
+ {4096, 4096, 4096, 33554432}, DT_FLOAT)));
}
TEST(UtilsTest, CalculateOutputSize) {
diff --git a/tensorflow/core/grappler/mutable_graph_view.cc b/tensorflow/core/grappler/mutable_graph_view.cc
index 5119acd6141270..4503c90cf466a9 100644
--- a/tensorflow/core/grappler/mutable_graph_view.cc
+++ b/tensorflow/core/grappler/mutable_graph_view.cc
@@ -68,6 +68,9 @@ bool IsIdentityConsumingSwitch(const MutableGraphView& graph,
}
NodeDef* input_node = graph.GetNode(tensor_id.node());
+ if (input_node == nullptr) {
+ return false;
+ }
return IsSwitch(*input_node);
}
return false;
diff --git a/tensorflow/core/grappler/optimizers/auto_parallel.cc b/tensorflow/core/grappler/optimizers/auto_parallel.cc
index a537fa256babba..e4e8009f9ccb20 100644
--- a/tensorflow/core/grappler/optimizers/auto_parallel.cc
+++ b/tensorflow/core/grappler/optimizers/auto_parallel.cc
@@ -152,7 +152,7 @@ Status AutoParallel::Initialize(const GrapplerItem& item) {
TF_RETURN_IF_ERROR(ComputeTransitiveFanin(graph_, item.fetch, &train_nodes));
LOG(INFO) << "Number of training nodes: " << train_nodes.size();
- const NodeDef* dequeue_node;
+ const NodeDef* dequeue_node = nullptr;
for (const auto& train_node : train_nodes) {
if (IsDequeueOp(*train_node)) {
dequeue_node = train_node;
diff --git a/tensorflow/core/grappler/optimizers/auto_parallel_test.cc b/tensorflow/core/grappler/optimizers/auto_parallel_test.cc
index 1c3186f1ee6e68..3af03a09613883 100644
--- a/tensorflow/core/grappler/optimizers/auto_parallel_test.cc
+++ b/tensorflow/core/grappler/optimizers/auto_parallel_test.cc
@@ -126,6 +126,30 @@ TEST_F(AutoParallelTest, SimpleParallel) {
EXPECT_EQ("^AutoParallel-Control-Fetch", node_gradient.input(0));
}
+TEST_F(AutoParallelTest, SimpleParallelNoDequeue) {
+ tensorflow::Scope s = tensorflow::Scope::DisabledShapeInferenceScope();
+ Output constant_a = ops::Const(s.WithOpName("constant_a"), 1.0f, {1});
+ Output constant_c = ops::Const(s.WithOpName("constant_c"), 1.0f, {1});
+ Output constant_b = ops::Const(s.WithOpName("constant_b"), 1, {1});
+ Output var = ops::Variable(s.WithOpName("var"), {1}, DT_FLOAT);
+ Output assign = ops::Assign(s.WithOpName("assign"), {var}, {constant_a});
+ Output add = ops::AddN(s.WithOpName("add"), {constant_a, constant_c});
+ Output learning_rate = ops::Const(s.WithOpName("learning_rate"), 0.01f, {1});
+ Output apply_gradient = ops::ApplyGradientDescent(
+ s.WithOpName("apply_gradient"), {var}, {learning_rate}, {add});
+
+ GrapplerItem item;
+ item.init_ops.push_back("assign");
+ item.fetch.push_back("apply_gradient");
+ item.init_ops.push_back("assign");
+ TF_CHECK_OK(s.ToGraphDef(&item.graph));
+
+ AutoParallel parallel(2);
+ GraphDef output;
+ Status status = parallel.Optimize(nullptr, item, &output);
+ TF_EXPECT_OK(status);
+}
+
} // namespace
} // namespace grappler
} // namespace tensorflow
diff --git a/tensorflow/core/grappler/optimizers/constant_folding.cc b/tensorflow/core/grappler/optimizers/constant_folding.cc
index df4cc54757134a..db88130b4afbc5 100644
--- a/tensorflow/core/grappler/optimizers/constant_folding.cc
+++ b/tensorflow/core/grappler/optimizers/constant_folding.cc
@@ -1013,7 +1013,12 @@ bool ConstantFolding::IsFoldableUncached(
}
}
for (const auto& output_prop : output_props) {
- const PartialTensorShape output_shape(output_prop.shape());
+ PartialTensorShape output_shape;
+ if (!PartialTensorShape::BuildPartialTensorShape(output_prop.shape(),
+ &output_shape)
+ .ok()) {
+ return false;
+ }
if (output_shape.IsFullyDefined()) {
const int64 num_bytes =
output_shape.num_elements() * DataTypeSize(output_prop.dtype());
@@ -1350,6 +1355,11 @@ Status ConstantFolding::EvaluateOneFoldable(const NodeDef& node,
}
TF_RETURN_IF_ERROR(CheckAttrExists(*input_node, "value"));
const TensorProto& raw_val = input_node->attr().at("value").tensor();
+ if (IsRefType(raw_val.dtype())) {
+ return errors::InvalidArgument(
+ "Not allowed to construct a tensor with reference dtype, got ",
+ DataTypeString(raw_val.dtype()));
+ }
Tensor* value = new Tensor(raw_val.dtype(), raw_val.tensor_shape());
CHECK(value->FromProto(raw_val))
<< "Unable to make Tensor from proto for " << node.name()
@@ -1665,15 +1675,21 @@ Status ConstantFolding::FoldGraph(
return Status::OK();
}
-bool ConstantFolding::IsSimplifiableReshape(
+Status ConstantFolding::IsSimplifiableReshape(
const NodeDef& node, const GraphProperties& properties) const {
if (!IsReshape(node)) {
- return false;
+ return errors::Internal("Node ", node.name(), " is not a Reshape node");
+ }
+ if (2 > node.input_size()) {
+ return errors::Internal("Node ", node.name(),
+ " must have at most 2 inputs but has ",
+ node.input_size());
}
- CHECK_LE(2, node.input_size());
const NodeDef* new_shape = node_map_->GetNode(node.input(1));
if (!IsReallyConstant(*new_shape)) {
- return false;
+ return errors::Internal("Node ", node.name(), " has shape ",
+ new_shape->DebugString(),
+ " which is not a constant");
}
TensorVector outputs;
auto outputs_cleanup = gtl::MakeCleanup([&outputs] {
@@ -1684,22 +1700,29 @@ bool ConstantFolding::IsSimplifiableReshape(
Status s = EvaluateNode(*new_shape, TensorVector(), &outputs);
if (!s.ok()) {
- return false;
+ return errors::Internal("Could not evaluate node ", node.name());
+ }
+ if (outputs.size() != 1) {
+ return errors::Internal("Node ", node.name(),
+ " must have exactly 1 output but has ",
+ outputs.size());
}
- CHECK_EQ(1, outputs.size());
const std::vector& props =
properties.GetInputProperties(node.name());
if (props.empty()) {
- return false;
+ return errors::Internal("Node ", node.name(), " has no properties");
}
const OpInfo::TensorProperties& prop = props[0];
if (prop.dtype() == DT_INVALID) {
- return false;
+ return errors::Internal("Node ", node.name(), " has property ",
+ prop.DebugString(), " with invalid dtype");
}
const PartialTensorShape shape(prop.shape());
if (!shape.IsFullyDefined()) {
- return false;
+ return errors::Internal("Node ", node.name(), " has property ",
+ prop.DebugString(), " with shape ",
+ shape.DebugString(), " which is not fully defined");
}
PartialTensorShape new_dims;
@@ -1709,17 +1732,24 @@ bool ConstantFolding::IsSimplifiableReshape(
int32 dim = outputs[0]->flat()(i);
shp.push_back(dim);
}
- TF_CHECK_OK(TensorShapeUtils::MakeShape(shp, &new_dims));
+ s = TensorShapeUtils::MakeShape(shp, &new_dims);
+ if (!s.ok()) return s;
} else {
std::vector shp;
for (int i = 0; i < outputs[0]->NumElements(); ++i) {
int64 dim = outputs[0]->flat()(i);
shp.push_back(dim);
}
- TF_CHECK_OK(TensorShapeUtils::MakeShape(shp, &new_dims));
+ s = TensorShapeUtils::MakeShape(shp, &new_dims);
+ if (!s.ok()) return s;
}
- return shape.IsCompatibleWith(new_dims);
+ if (!shape.IsCompatibleWith(new_dims)) {
+ return errors::Internal("Expected shape ", shape.DebugString(),
+ "to be compatible with ", new_dims.DebugString());
+ }
+
+ return Status::OK();
}
#define IS_VALUE_CASE(DTYPE, VALUE) \
@@ -2905,7 +2935,7 @@ bool ConstantFolding::SimplifyReduction(GraphDef* optimized_graph,
bool ConstantFolding::SimplifyReshape(const GraphProperties& properties,
bool use_shape_info, NodeDef* node) {
if (!use_shape_info || node->attr().count("T") == 0 ||
- !IsSimplifiableReshape(*node, properties)) {
+ !IsSimplifiableReshape(*node, properties).ok()) {
return false;
}
DataType output_type = node->attr().at("T").type();
@@ -3454,6 +3484,9 @@ bool ConstantFolding::MulConvPushDown(GraphDef* optimized_graph, NodeDef* node,
NodeDef* mul_left_child = node_map_->GetNode(node->input(0));
NodeDef* mul_right_child = node_map_->GetNode(node->input(1));
+ if (mul_left_child == nullptr || mul_right_child == nullptr) {
+ return false;
+ }
// One child must be constant, and the second must be Conv op.
const bool left_child_is_constant = IsReallyConstant(*mul_left_child);
const bool right_child_is_constant = IsReallyConstant(*mul_right_child);
diff --git a/tensorflow/core/grappler/optimizers/constant_folding.h b/tensorflow/core/grappler/optimizers/constant_folding.h
index 8462f002021998..0d16f1ade61c3b 100644
--- a/tensorflow/core/grappler/optimizers/constant_folding.h
+++ b/tensorflow/core/grappler/optimizers/constant_folding.h
@@ -132,8 +132,8 @@ class ConstantFolding : public GraphOptimizer {
Status FoldGraph(const GraphProperties& properties, GraphDef* output,
absl::flat_hash_set* nodes_to_not_simplify);
- bool IsSimplifiableReshape(const NodeDef& node,
- const GraphProperties& properties) const;
+ Status IsSimplifiableReshape(const NodeDef& node,
+ const GraphProperties& properties) const;
Status SimplifyGraph(bool use_shape_info, GraphDef* optimized_graph,
GraphProperties* properties,
absl::flat_hash_set* nodes_to_not_simplify);
diff --git a/tensorflow/core/grappler/optimizers/dependency_optimizer.cc b/tensorflow/core/grappler/optimizers/dependency_optimizer.cc
index 1be7f2692e0f76..0f1bbb729edd23 100644
--- a/tensorflow/core/grappler/optimizers/dependency_optimizer.cc
+++ b/tensorflow/core/grappler/optimizers/dependency_optimizer.cc
@@ -75,8 +75,10 @@ bool DependencyOptimizer::SafeToRemoveIdentity(const NodeDef& node) const {
}
const NodeDef* input = node_map_->GetNode(NodeName(node.input(0)));
- CHECK(input != nullptr) << "node = " << node.name()
- << " input = " << node.input(0);
+ if (input == nullptr) {
+ VLOG(1) << "node = " << node.name() << " input = " << node.input(0);
+ return false;
+ }
// Don't remove Identity nodes corresponding to Variable reads or following
// Recv.
if (IsVariable(*input) || IsRecv(*input)) {
diff --git a/tensorflow/core/kernels/assign_op.h b/tensorflow/core/kernels/assign_op.h
index 74f926bdc88bf7..8aa56e2e29ed0b 100644
--- a/tensorflow/core/kernels/assign_op.h
+++ b/tensorflow/core/kernels/assign_op.h
@@ -50,6 +50,12 @@ class AssignOp : public OpKernel {
// We always return the input ref.
context->forward_ref_input_to_ref_output(0, 0);
+ // Prevent copying uninitialized data, to solve harder to debug undefined
+ // behaviors that cannot be traced back to the original tensor.
+ OP_REQUIRES(
+ context, rhs.IsInitialized(),
+ errors::Internal("Right hand side of AssignOp is not initialized"));
+
// We can't always know how this value will be used downstream, so make
// conservative assumptions in specifying constraints on the memory
// allocation attributes, unless the Grappler graph analysis determined that
diff --git a/tensorflow/core/kernels/bincount_op.cc b/tensorflow/core/kernels/bincount_op.cc
index 258266ab29d33f..5c2ee797e62cea 100644
--- a/tensorflow/core/kernels/bincount_op.cc
+++ b/tensorflow/core/kernels/bincount_op.cc
@@ -235,6 +235,9 @@ class DenseBincountOp : public OpKernel {
const Tensor& size_t = ctx->input(1);
const Tensor& weights = ctx->input(2);
+ OP_REQUIRES(ctx, size_t.dims() == 0,
+ errors::InvalidArgument("Shape must be rank 0 but is rank ",
+ size_t.dims()));
Tidx size = size_t.scalar()();
OP_REQUIRES(
ctx, size >= 0,
@@ -331,6 +334,9 @@ class SparseBincountOp : public OpKernel {
const auto weights = ctx->input(4).flat();
const int64 weights_size = weights.size();
+ OP_REQUIRES(ctx, size_t.dims() == 0,
+ errors::InvalidArgument("Shape must be rank 0 but is rank ",
+ size_t.dims()));
Tidx size = size_t.scalar()();
OP_REQUIRES(
ctx, size >= 0,
@@ -364,6 +370,16 @@ class SparseBincountOp : public OpKernel {
for (int64 i = 0; i < indices_mat.dimension(0); ++i) {
const int64 batch = indices_mat(i, 0);
const Tidx bin = values(i);
+ OP_REQUIRES(
+ ctx, batch < out.dimension(0),
+ errors::InvalidArgument("Index out of bound. `batch` (", batch,
+ ") must be less than the dimension size (",
+ out.dimension(0), ")."));
+ OP_REQUIRES(
+ ctx, bin < out.dimension(1),
+ errors::InvalidArgument("Index out ouf bound. `bin` (", bin,
+ ") must be less then the dimension size (",
+ out.dimension(1), ")."));
if (bin < size) {
if (binary_output_) {
out(batch, bin) = T(1);
@@ -411,6 +427,9 @@ class RaggedBincountOp : public OpKernel {
const auto weights = ctx->input(3).flat();
const int64 weights_size = weights.size();
+ OP_REQUIRES(ctx, size_t.dims() == 0,
+ errors::InvalidArgument("Shape must be rank 0 but is rank ",
+ size_t.dims()));
Tidx size = size_t.scalar()();
OP_REQUIRES(
ctx, size >= 0,
diff --git a/tensorflow/core/kernels/boosted_trees/prediction_ops.cc b/tensorflow/core/kernels/boosted_trees/prediction_ops.cc
index 008962c33ecb10..3da2efd3530432 100644
--- a/tensorflow/core/kernels/boosted_trees/prediction_ops.cc
+++ b/tensorflow/core/kernels/boosted_trees/prediction_ops.cc
@@ -37,7 +37,7 @@ limitations under the License.
namespace tensorflow {
static void ConvertVectorsToMatrices(
- const OpInputList bucketized_features_list,
+ OpKernelContext* const context, const OpInputList bucketized_features_list,
std::vector::ConstMatrix>& bucketized_features) {
for (const Tensor& tensor : bucketized_features_list) {
if (tensor.dims() == 1) {
@@ -45,6 +45,10 @@ static void ConvertVectorsToMatrices(
bucketized_features.emplace_back(
TTypes::ConstMatrix(v.data(), v.size(), 1));
} else {
+ OP_REQUIRES(context, TensorShapeUtils::IsMatrix(tensor.shape()),
+ errors::Internal("Cannot use tensor as matrix, expected "
+ "vector or matrix, received shape ",
+ tensor.shape().DebugString()));
bucketized_features.emplace_back(tensor.matrix());
}
}
@@ -58,6 +62,9 @@ class BoostedTreesTrainingPredictOp : public OpKernel {
public:
explicit BoostedTreesTrainingPredictOp(OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr("num_bucketized_features",
&num_bucketized_features_));
OP_REQUIRES_OK(context,
@@ -76,17 +83,26 @@ class BoostedTreesTrainingPredictOp : public OpKernel {
&bucketized_features_list));
std::vector::ConstMatrix> bucketized_features;
bucketized_features.reserve(bucketized_features_list.size());
- ConvertVectorsToMatrices(bucketized_features_list, bucketized_features);
+ ConvertVectorsToMatrices(context, bucketized_features_list,
+ bucketized_features);
const int batch_size = bucketized_features[0].dimension(0);
const Tensor* cached_tree_ids_t;
OP_REQUIRES_OK(context,
context->input("cached_tree_ids", &cached_tree_ids_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsVector(cached_tree_ids_t->shape()),
+ errors::InvalidArgument(
+ "cached_tree_ids must be a vector, received shape ",
+ cached_tree_ids_t->shape().DebugString()));
const auto cached_tree_ids = cached_tree_ids_t->vec();
const Tensor* cached_node_ids_t;
OP_REQUIRES_OK(context,
context->input("cached_node_ids", &cached_node_ids_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsVector(cached_node_ids_t->shape()),
+ errors::InvalidArgument(
+ "cached_node_ids must be a vector, received shape ",
+ cached_node_ids_t->shape().DebugString()));
const auto cached_node_ids = cached_node_ids_t->vec();
// Allocate outputs.
@@ -118,9 +134,9 @@ class BoostedTreesTrainingPredictOp : public OpKernel {
output_partial_logits.setZero();
} else {
output_tree_ids.setConstant(latest_tree);
- auto do_work = [&resource, &bucketized_features, &cached_tree_ids,
- &cached_node_ids, &output_partial_logits,
- &output_node_ids, latest_tree,
+ auto do_work = [&context, &resource, &bucketized_features,
+ &cached_tree_ids, &cached_node_ids,
+ &output_partial_logits, &output_node_ids, latest_tree,
this](int64 start, int64 end) {
for (int32 i = start; i < end; ++i) {
int32 tree_id = cached_tree_ids(i);
@@ -138,7 +154,11 @@ class BoostedTreesTrainingPredictOp : public OpKernel {
// node's value. The following logic handles both of these cases.
const auto& node_logits = resource->node_value(tree_id, node_id);
if (!node_logits.empty()) {
- DCHECK_EQ(node_logits.size(), logits_dimension_);
+ OP_REQUIRES(
+ context, node_logits.size() == logits_dimension_,
+ errors::Internal(
+ "Expected node_logits.size() == logits_dimension_, got ",
+ node_logits.size(), " vs ", logits_dimension_));
for (int32 j = 0; j < logits_dimension_; ++j) {
partial_tree_logits[j] -= node_logits[j];
}
@@ -151,7 +171,11 @@ class BoostedTreesTrainingPredictOp : public OpKernel {
while (true) {
if (resource->is_leaf(tree_id, node_id)) {
const auto& leaf_logits = resource->node_value(tree_id, node_id);
- DCHECK_EQ(leaf_logits.size(), logits_dimension_);
+ OP_REQUIRES(
+ context, leaf_logits.size() == logits_dimension_,
+ errors::Internal(
+ "Expected leaf_logits.size() == logits_dimension_, got ",
+ leaf_logits.size(), " vs ", logits_dimension_));
// Tree is done
const float tree_weight = resource->GetTreeWeight(tree_id);
for (int32 j = 0; j < logits_dimension_; ++j) {
@@ -201,6 +225,9 @@ class BoostedTreesPredictOp : public OpKernel {
public:
explicit BoostedTreesPredictOp(OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr("num_bucketized_features",
&num_bucketized_features_));
OP_REQUIRES_OK(context,
@@ -219,7 +246,8 @@ class BoostedTreesPredictOp : public OpKernel {
&bucketized_features_list));
std::vector::ConstMatrix> bucketized_features;
bucketized_features.reserve(bucketized_features_list.size());
- ConvertVectorsToMatrices(bucketized_features_list, bucketized_features);
+ ConvertVectorsToMatrices(context, bucketized_features_list,
+ bucketized_features);
const int batch_size = bucketized_features[0].dimension(0);
// Allocate outputs.
@@ -236,8 +264,8 @@ class BoostedTreesPredictOp : public OpKernel {
}
const int32 last_tree = resource->num_trees() - 1;
- auto do_work = [&resource, &bucketized_features, &output_logits, last_tree,
- this](int64 start, int64 end) {
+ auto do_work = [&context, &resource, &bucketized_features, &output_logits,
+ last_tree, this](int64_t start, int64_t end) {
for (int32 i = start; i < end; ++i) {
std::vector tree_logits(logits_dimension_, 0.0);
int32 tree_id = 0;
@@ -246,7 +274,11 @@ class BoostedTreesPredictOp : public OpKernel {
if (resource->is_leaf(tree_id, node_id)) {
const float tree_weight = resource->GetTreeWeight(tree_id);
const auto& leaf_logits = resource->node_value(tree_id, node_id);
- DCHECK_EQ(leaf_logits.size(), logits_dimension_);
+ OP_REQUIRES(
+ context, leaf_logits.size() == logits_dimension_,
+ errors::Internal(
+ "Expected leaf_logits.size() == logits_dimension_, got ",
+ leaf_logits.size(), " vs ", logits_dimension_));
for (int32 j = 0; j < logits_dimension_; ++j) {
tree_logits[j] += tree_weight * leaf_logits[j];
}
@@ -298,6 +330,9 @@ class BoostedTreesExampleDebugOutputsOp : public OpKernel {
explicit BoostedTreesExampleDebugOutputsOp(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr("num_bucketized_features",
&num_bucketized_features_));
OP_REQUIRES_OK(context,
@@ -319,7 +354,8 @@ class BoostedTreesExampleDebugOutputsOp : public OpKernel {
&bucketized_features_list));
std::vector::ConstMatrix> bucketized_features;
bucketized_features.reserve(bucketized_features_list.size());
- ConvertVectorsToMatrices(bucketized_features_list, bucketized_features);
+ ConvertVectorsToMatrices(context, bucketized_features_list,
+ bucketized_features);
const int batch_size = bucketized_features[0].dimension(0);
// We need to get the feature ids used for splitting and the logits after
@@ -339,14 +375,16 @@ class BoostedTreesExampleDebugOutputsOp : public OpKernel {
// features used to split and the associated logits at each point along the
// path. Note: feature_ids has one less value than logits_path because the
// first value of each logit path will be the bias.
- auto do_work = [&resource, &bucketized_features, &output_debug_info,
- last_tree](int64 start, int64 end) {
+ auto do_work = [&context, &resource, &bucketized_features,
+ &output_debug_info, last_tree](int64_t start, int64_t end) {
for (int32 i = start; i < end; ++i) {
// Proto to store debug outputs, per example.
boosted_trees::DebugOutput example_debug_info;
// Initial bias prediction. E.g., prediction based off training mean.
const auto& tree_logits = resource->node_value(0, 0);
- DCHECK_EQ(tree_logits.size(), 1);
+ OP_REQUIRES(context, tree_logits.size() == 1,
+ errors::Internal("Expected tree_logits.size() == 1, got ",
+ tree_logits.size()));
float tree_logit = resource->GetTreeWeight(0) * tree_logits[0];
example_debug_info.add_logits_path(tree_logit);
int32 node_id = 0;
@@ -372,7 +410,10 @@ class BoostedTreesExampleDebugOutputsOp : public OpKernel {
node_id =
resource->next_node(tree_id, node_id, i, bucketized_features);
const auto& tree_logits = resource->node_value(tree_id, node_id);
- DCHECK_EQ(tree_logits.size(), 1);
+ OP_REQUIRES(
+ context, tree_logits.size() == 1,
+ errors::Internal("Expected tree_logits.size() == 1, got ",
+ tree_logits.size()));
tree_logit = resource->GetTreeWeight(tree_id) * tree_logits[0];
// Output logit incorporates sum of leaf logits from prior trees.
example_debug_info.add_logits_path(tree_logit + past_trees_logit);
diff --git a/tensorflow/core/kernels/boosted_trees/quantile_ops.cc b/tensorflow/core/kernels/boosted_trees/quantile_ops.cc
index 0065bdd66aa708..5d4fd8c6778ff8 100644
--- a/tensorflow/core/kernels/boosted_trees/quantile_ops.cc
+++ b/tensorflow/core/kernels/boosted_trees/quantile_ops.cc
@@ -98,6 +98,9 @@ class BoostedTreesCreateQuantileStreamResourceOp : public OpKernel {
explicit BoostedTreesCreateQuantileStreamResourceOp(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr(kMaxElementsName, &max_elements_));
}
@@ -108,6 +111,10 @@ class BoostedTreesCreateQuantileStreamResourceOp : public OpKernel {
// disallowed.
const Tensor* epsilon_t;
OP_REQUIRES_OK(context, context->input(kEpsilonName, &epsilon_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(epsilon_t->shape()),
+ errors::InvalidArgument(
+ "epsilon must be a scalar, got a tensor of shape ",
+ epsilon_t->shape().DebugString()));
float epsilon = epsilon_t->scalar()();
OP_REQUIRES(
context, epsilon > 0,
@@ -115,7 +122,14 @@ class BoostedTreesCreateQuantileStreamResourceOp : public OpKernel {
const Tensor* num_streams_t;
OP_REQUIRES_OK(context, context->input(kNumStreamsName, &num_streams_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(num_streams_t->shape()),
+ errors::InvalidArgument(
+ "num_streams must be a scalar, got a tensor of shape ",
+ num_streams_t->shape().DebugString()));
int64 num_streams = num_streams_t->scalar()();
+ OP_REQUIRES(context, num_streams >= 0,
+ errors::InvalidArgument(
+ "Num_streams input cannot be a negative integer"));
auto result =
new QuantileStreamResource(epsilon, max_elements_, num_streams);
@@ -140,6 +154,9 @@ class BoostedTreesMakeQuantileSummariesOp : public OpKernel {
explicit BoostedTreesMakeQuantileSummariesOp(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr(kNumFeaturesName, &num_features_));
}
@@ -153,7 +170,8 @@ class BoostedTreesMakeQuantileSummariesOp : public OpKernel {
const Tensor* example_weights_t;
OP_REQUIRES_OK(context,
context->input(kExampleWeightsName, &example_weights_t));
- DCHECK(float_features_list.size() > 0) << "Got empty feature list";
+ OP_REQUIRES(context, float_features_list.size() > 0,
+ errors::Internal("Got empty feature list"));
auto example_weights = example_weights_t->flat();
const int64 weight_size = example_weights.size();
const int64 batch_size = float_features_list[0].flat().size();
@@ -163,6 +181,10 @@ class BoostedTreesMakeQuantileSummariesOp : public OpKernel {
"Weights should be a single value or same size as features.")));
const Tensor* epsilon_t;
OP_REQUIRES_OK(context, context->input(kEpsilonName, &epsilon_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(epsilon_t->shape()),
+ errors::InvalidArgument(
+ "epsilon must be a scalar, got a tensor of shape ",
+ epsilon_t->shape().DebugString()));
float epsilon = epsilon_t->scalar()();
OpOutputList summaries_output_list;
@@ -187,7 +209,8 @@ class BoostedTreesMakeQuantileSummariesOp : public OpKernel {
context,
summaries_output_list.allocate(
index,
- TensorShape({static_cast(summary_entry_list.size()), 4}),
+ TensorShape(
+ {static_cast(summary_entry_list.size()), 4}),
&output_t));
auto output = output_t->matrix();
for (auto row = 0; row < summary_entry_list.size(); row++) {
@@ -220,6 +243,9 @@ class BoostedTreesFlushQuantileSummariesOp : public OpKernel {
explicit BoostedTreesFlushQuantileSummariesOp(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr(kNumFeaturesName, &num_features_));
}
@@ -279,7 +305,11 @@ class BoostedTreesQuantileStreamResourceAddSummariesOp : public OpKernel {
public:
explicit BoostedTreesQuantileStreamResourceAddSummariesOp(
OpKernelConstruction* const context)
- : OpKernel(context) {}
+ : OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
+ }
void Compute(OpKernelContext* context) override {
ResourceHandle handle;
@@ -295,7 +325,10 @@ class BoostedTreesQuantileStreamResourceAddSummariesOp : public OpKernel {
OP_REQUIRES_OK(context,
context->input_list(kSummariesName, &summaries_list));
int32 num_streams = stream_resource->num_streams();
- CHECK_EQ(static_cast(num_streams), summaries_list.size());
+ OP_REQUIRES(
+ context, num_streams == summaries_list.size(),
+ errors::Internal("Expected num_streams == summaries_list.size(), got ",
+ num_streams, " vs ", summaries_list.size()));
auto do_quantile_add_summary = [&](const int64 begin, const int64 end) {
// Iterating all features.
@@ -310,7 +343,10 @@ class BoostedTreesQuantileStreamResourceAddSummariesOp : public OpKernel {
const auto summary_values = summaries.matrix();
const auto& tensor_shape = summaries.shape();
const int64 entries_size = tensor_shape.dim_size(0);
- CHECK_EQ(tensor_shape.dim_size(1), 4);
+ OP_REQUIRES(
+ context, tensor_shape.dim_size(1) == 4,
+ errors::Internal("Expected tensor_shape.dim_size(1) == 4, got ",
+ tensor_shape.dim_size(1)));
std::vector summary_entries;
summary_entries.reserve(entries_size);
for (int64 i = 0; i < entries_size; i++) {
@@ -343,6 +379,9 @@ class BoostedTreesQuantileStreamResourceDeserializeOp : public OpKernel {
explicit BoostedTreesQuantileStreamResourceDeserializeOp(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr(kNumStreamsName, &num_features_));
}
@@ -362,6 +401,12 @@ class BoostedTreesQuantileStreamResourceDeserializeOp : public OpKernel {
// Iterating over all streams.
for (int64 stream_idx = begin; stream_idx < end; stream_idx++) {
const Tensor& bucket_boundaries_t = bucket_boundaries_list[stream_idx];
+ OP_REQUIRES(
+ context, TensorShapeUtils::IsVector(bucket_boundaries_t.shape()),
+ errors::InvalidArgument("bucket boundaries for each stream must be "
+ "a vector, received shape ",
+ bucket_boundaries_t.shape().DebugString(),
+ " for stream ", stream_idx));
const auto& bucket_boundaries = bucket_boundaries_t.vec();
std::vector result;
result.reserve(bucket_boundaries.size());
@@ -393,6 +438,9 @@ class BoostedTreesQuantileStreamResourceFlushOp : public OpKernel {
explicit BoostedTreesQuantileStreamResourceFlushOp(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context,
context->GetAttr(kGenerateQuantiles, &generate_quantiles_));
}
@@ -409,6 +457,10 @@ class BoostedTreesQuantileStreamResourceFlushOp : public OpKernel {
const Tensor* num_buckets_t;
OP_REQUIRES_OK(context, context->input(kNumBucketsName, &num_buckets_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(num_buckets_t->shape()),
+ errors::InvalidArgument(
+ "num_buckets must be a scalar, got a tensor of shape ",
+ num_buckets_t->shape().DebugString()));
const int64 num_buckets = num_buckets_t->scalar()();
const int64 num_streams = stream_resource->num_streams();
@@ -449,6 +501,9 @@ class BoostedTreesQuantileStreamResourceGetBucketBoundariesOp
explicit BoostedTreesQuantileStreamResourceGetBucketBoundariesOp(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr(kNumFeaturesName, &num_features_));
}
@@ -463,7 +518,9 @@ class BoostedTreesQuantileStreamResourceGetBucketBoundariesOp
mutex_lock l(*stream_resource->mutex());
const int64 num_streams = stream_resource->num_streams();
- CHECK_EQ(num_features_, num_streams);
+ OP_REQUIRES(context, num_streams == num_features_,
+ errors::Internal("Expected num_streams == num_features_, got ",
+ num_streams, " vs ", num_features_));
OpOutputList bucket_boundaries_list;
OP_REQUIRES_OK(context, context->output_list(kBucketBoundariesName,
&bucket_boundaries_list));
@@ -473,10 +530,10 @@ class BoostedTreesQuantileStreamResourceGetBucketBoundariesOp
for (int64 stream_idx = begin; stream_idx < end; stream_idx++) {
const auto& boundaries = stream_resource->boundaries(stream_idx);
Tensor* bucket_boundaries_t = nullptr;
- OP_REQUIRES_OK(context,
- bucket_boundaries_list.allocate(
- stream_idx, {static_cast(boundaries.size())},
- &bucket_boundaries_t));
+ OP_REQUIRES_OK(
+ context, bucket_boundaries_list.allocate(
+ stream_idx, {static_cast(boundaries.size())},
+ &bucket_boundaries_t));
auto* quantiles_flat = bucket_boundaries_t->flat().data();
memcpy(quantiles_flat, boundaries.data(),
sizeof(float) * boundaries.size());
@@ -507,6 +564,9 @@ class BoostedTreesBucketizeOp : public OpKernel {
public:
explicit BoostedTreesBucketizeOp(OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr(kNumFeaturesName, &num_features_));
}
diff --git a/tensorflow/core/kernels/boosted_trees/resource_ops.cc b/tensorflow/core/kernels/boosted_trees/resource_ops.cc
index ac1fb5652da5f9..2e55efb19dc597 100644
--- a/tensorflow/core/kernels/boosted_trees/resource_ops.cc
+++ b/tensorflow/core/kernels/boosted_trees/resource_ops.cc
@@ -36,23 +36,38 @@ REGISTER_KERNEL_BUILDER(
class BoostedTreesCreateEnsembleOp : public OpKernel {
public:
explicit BoostedTreesCreateEnsembleOp(OpKernelConstruction* context)
- : OpKernel(context) {}
+ : OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
+ }
void Compute(OpKernelContext* context) override {
// Get the stamp token.
const Tensor* stamp_token_t;
OP_REQUIRES_OK(context, context->input("stamp_token", &stamp_token_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(stamp_token_t->shape()),
+ errors::InvalidArgument(
+ "stamp_token must be a scalar, got a tensor of shape ",
+ stamp_token_t->shape().DebugString()));
int64 stamp_token = stamp_token_t->scalar()();
// Get the tree ensemble proto.
const Tensor* tree_ensemble_serialized_t;
OP_REQUIRES_OK(context, context->input("tree_ensemble_serialized",
&tree_ensemble_serialized_t));
+ OP_REQUIRES(
+ context,
+ TensorShapeUtils::IsScalar(tree_ensemble_serialized_t->shape()),
+ errors::InvalidArgument(
+ "tree_ensemble_serialized must be a scalar, got a tensor of shape ",
+ tree_ensemble_serialized_t->shape().DebugString()));
std::unique_ptr result(
new BoostedTreesEnsembleResource());
if (!result->InitFromSerialized(
tree_ensemble_serialized_t->scalar()(), stamp_token)) {
result->Unref();
+ result.release(); // Needed due to the `->Unref` above, to prevent UAF
OP_REQUIRES(
context, false,
errors::InvalidArgument("Unable to parse tree ensemble proto."));
@@ -75,7 +90,11 @@ REGISTER_KERNEL_BUILDER(Name("BoostedTreesCreateEnsemble").Device(DEVICE_CPU),
class BoostedTreesGetEnsembleStatesOp : public OpKernel {
public:
explicit BoostedTreesGetEnsembleStatesOp(OpKernelConstruction* context)
- : OpKernel(context) {}
+ : OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
+ }
void Compute(OpKernelContext* context) override {
// Looks up the resource.
@@ -138,7 +157,11 @@ REGISTER_KERNEL_BUILDER(
class BoostedTreesSerializeEnsembleOp : public OpKernel {
public:
explicit BoostedTreesSerializeEnsembleOp(OpKernelConstruction* context)
- : OpKernel(context) {}
+ : OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
+ }
void Compute(OpKernelContext* context) override {
core::RefCountPtr tree_ensemble_resource;
@@ -165,7 +188,11 @@ REGISTER_KERNEL_BUILDER(
class BoostedTreesDeserializeEnsembleOp : public OpKernel {
public:
explicit BoostedTreesDeserializeEnsembleOp(OpKernelConstruction* context)
- : OpKernel(context) {}
+ : OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
+ }
void Compute(OpKernelContext* context) override {
core::RefCountPtr tree_ensemble_resource;
@@ -176,12 +203,22 @@ class BoostedTreesDeserializeEnsembleOp : public OpKernel {
// Get the stamp token.
const Tensor* stamp_token_t;
OP_REQUIRES_OK(context, context->input("stamp_token", &stamp_token_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(stamp_token_t->shape()),
+ errors::InvalidArgument(
+ "stamp_token must be a scalar, got a tensor of shape ",
+ stamp_token_t->shape().DebugString()));
int64 stamp_token = stamp_token_t->scalar()();
// Get the tree ensemble proto.
const Tensor* tree_ensemble_serialized_t;
OP_REQUIRES_OK(context, context->input("tree_ensemble_serialized",
&tree_ensemble_serialized_t));
+ OP_REQUIRES(
+ context,
+ TensorShapeUtils::IsScalar(tree_ensemble_serialized_t->shape()),
+ errors::InvalidArgument(
+ "tree_ensemble_serialized must be a scalar, got a tensor of shape ",
+ tree_ensemble_serialized_t->shape().DebugString()));
// Deallocate all the previous objects on the resource.
tree_ensemble_resource->Reset();
OP_REQUIRES(
diff --git a/tensorflow/core/kernels/boosted_trees/stats_ops.cc b/tensorflow/core/kernels/boosted_trees/stats_ops.cc
index 851e5b78e847b7..9090876afc8681 100644
--- a/tensorflow/core/kernels/boosted_trees/stats_ops.cc
+++ b/tensorflow/core/kernels/boosted_trees/stats_ops.cc
@@ -14,6 +14,7 @@ limitations under the License.
==============================================================================*/
#include
+#include
#include
#include "third_party/eigen3/Eigen/Core"
@@ -22,6 +23,7 @@ limitations under the License.
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/kernels/boosted_trees/boosted_trees.pb.h"
#include "tensorflow/core/kernels/boosted_trees/tree_helper.h"
+#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/platform/logging.h"
namespace tensorflow {
@@ -43,6 +45,9 @@ class BoostedTreesCalculateBestGainsPerFeatureOp : public OpKernel {
explicit BoostedTreesCalculateBestGainsPerFeatureOp(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr("max_splits", &max_splits_));
OP_REQUIRES_OK(context, context->GetAttr("num_features", &num_features_));
}
@@ -51,6 +56,16 @@ class BoostedTreesCalculateBestGainsPerFeatureOp : public OpKernel {
// node_id_range
const Tensor* node_id_range_t;
OP_REQUIRES_OK(context, context->input("node_id_range", &node_id_range_t));
+ OP_REQUIRES(
+ context, node_id_range_t->dims() == 1,
+ errors::InvalidArgument("node_id_range must be a rank 1 tensor, but "
+ "given node_id_range has dims of ",
+ node_id_range_t->dims()));
+ OP_REQUIRES(context, node_id_range_t->dim_size(0) == 2,
+ errors::InvalidArgument(
+ "node_id_range must be a rank 1 tensor with shape=[2], but "
+ "given node_id_range has shape ",
+ node_id_range_t->dim_size(0), " on its first dim"));
const auto node_id_range = node_id_range_t->vec();
const int32 node_id_first = node_id_range(0); // inclusive
const int32 node_id_last = node_id_range(1); // exclusive
@@ -60,7 +75,10 @@ class BoostedTreesCalculateBestGainsPerFeatureOp : public OpKernel {
&stats_summary_list));
const int64 num_buckets = stats_summary_list[0].dim_size(1);
// Check for single logit: 1 gradient + 1 hessian value.
- DCHECK_EQ(stats_summary_list[0].dim_size(2), 2);
+ OP_REQUIRES(context, stats_summary_list[0].dim_size(2) == 2,
+ errors::InvalidArgument("stats_summary_list[0] must have "
+ "exactly 2 dimensions, obtained: ",
+ stats_summary_list[0].dim_size(2)));
std::vector::ConstTensor> stats_summary;
stats_summary.reserve(stats_summary_list.size());
for (const auto& tensor : stats_summary_list) {
@@ -68,17 +86,33 @@ class BoostedTreesCalculateBestGainsPerFeatureOp : public OpKernel {
}
const Tensor* l1_t;
OP_REQUIRES_OK(context, context->input("l1", &l1_t));
+ OP_REQUIRES(
+ context, TensorShapeUtils::IsScalar(l1_t->shape()),
+ errors::InvalidArgument("l1 must be a scalar, got a tensor of shape ",
+ l1_t->shape().DebugString()));
const auto l1 = l1_t->scalar()();
const Tensor* l2_t;
OP_REQUIRES_OK(context, context->input("l2", &l2_t));
+ OP_REQUIRES(
+ context, TensorShapeUtils::IsScalar(l2_t->shape()),
+ errors::InvalidArgument("l2 must be a scalar, got a tensor of shape ",
+ l2_t->shape().DebugString()));
const auto l2 = l2_t->scalar()();
const Tensor* tree_complexity_t;
OP_REQUIRES_OK(context,
context->input("tree_complexity", &tree_complexity_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(tree_complexity_t->shape()),
+ errors::InvalidArgument(
+ "tree_complexity must be a scalar, got a tensor of shape ",
+ tree_complexity_t->shape().DebugString()));
const auto tree_complexity = tree_complexity_t->scalar()();
const Tensor* min_node_weight_t;
OP_REQUIRES_OK(context,
context->input("min_node_weight", &min_node_weight_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(min_node_weight_t->shape()),
+ errors::InvalidArgument(
+ "min_node_weight must be a scalar, got a tensor of shape ",
+ min_node_weight_t->shape().DebugString()));
const auto min_node_weight = min_node_weight_t->scalar()();
// Allocate output lists of tensors:
@@ -236,6 +270,9 @@ class BoostedTreesCalculateBestFeatureSplitOp : public OpKernel {
explicit BoostedTreesCalculateBestFeatureSplitOp(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr("logits_dimension", &logits_dim_));
OP_REQUIRES_OK(context, context->GetAttr("split_type", &split_type_));
}
@@ -244,12 +281,22 @@ class BoostedTreesCalculateBestFeatureSplitOp : public OpKernel {
// node_id_range
const Tensor* node_id_range_t;
OP_REQUIRES_OK(context, context->input("node_id_range", &node_id_range_t));
+ OP_REQUIRES(
+ context, node_id_range_t->NumElements() == 2,
+ errors::InvalidArgument("node_id_range argument must have shape [2]"));
+ OP_REQUIRES(context, TensorShapeUtils::IsVector(node_id_range_t->shape()),
+ errors::InvalidArgument(
+ "node_id_range must be a vector, received shape ",
+ node_id_range_t->shape().DebugString()));
const auto node_id_range = node_id_range_t->vec();
const int32 node_id_first = node_id_range(0); // inclusive
const int32 node_id_last = node_id_range(1); // exclusive
const Tensor* stats_summary_t;
OP_REQUIRES_OK(context, context->input("stats_summary", &stats_summary_t));
+ OP_REQUIRES(
+ context, stats_summary_t->shape().dims() == 4,
+ errors::InvalidArgument("stats_summary argument must have rank 4"));
TTypes::ConstTensor stats_summary =
stats_summary_t->tensor();
const int32 feature_dims = stats_summary_t->dim_size(1);
@@ -257,31 +304,51 @@ class BoostedTreesCalculateBestFeatureSplitOp : public OpKernel {
const int32 num_buckets = stats_summary_t->dim_size(2) - 1;
const int32 logits_dim = logits_dim_;
const int32 hessian_dim = stats_summary_t->dim_size(3) - logits_dim;
- DCHECK_GT(hessian_dim, 0);
- DCHECK_LE(hessian_dim, logits_dim * logits_dim);
+ OP_REQUIRES(context, hessian_dim > 0,
+ errors::InvalidArgument("hessian dim should be < 0, got ",
+ hessian_dim));
+ OP_REQUIRES(context, hessian_dim <= logits_dim * logits_dim,
+ errors::InvalidArgument(
+ "hessian dim should be <= ", logits_dim * logits_dim,
+ " but got: ", hessian_dim));
const Tensor* l1_t;
OP_REQUIRES_OK(context, context->input("l1", &l1_t));
+ OP_REQUIRES(context, l1_t->NumElements() == 1,
+ errors::InvalidArgument("l1 argument must be a scalar"));
const auto l1 = l1_t->scalar()();
- DCHECK_GE(l1, 0);
+ OP_REQUIRES(context, l1 >= 0,
+ errors::InvalidArgument("l1 = ", l1, " but it should be >= 0"));
if (logits_dim_ > 1) {
// Multi-class L1 regularization not supported yet.
- DCHECK_EQ(l1, 0);
+ OP_REQUIRES(
+ context, l1 == 0,
+ errors::InvalidArgument(
+ "l1 != 0 is not yet supported for multi-class regularization"));
}
const Tensor* l2_t;
OP_REQUIRES_OK(context, context->input("l2", &l2_t));
+ OP_REQUIRES(context, l2_t->NumElements() == 1,
+ errors::InvalidArgument("l2 argument must be a scalar"));
const auto l2 = l2_t->scalar()();
- DCHECK_GE(l2, 0);
+ OP_REQUIRES(context, l2 >= 0,
+ errors::InvalidArgument("l2 = ", l2, " but it should be >= 0"));
const Tensor* tree_complexity_t;
OP_REQUIRES_OK(context,
context->input("tree_complexity", &tree_complexity_t));
+ OP_REQUIRES(
+ context, tree_complexity_t->NumElements() == 1,
+ errors::InvalidArgument("tree_complexity argument must be a scalar"));
const auto tree_complexity = tree_complexity_t->scalar()();
const Tensor* min_node_weight_t;
OP_REQUIRES_OK(context,
context->input("min_node_weight", &min_node_weight_t));
+ OP_REQUIRES(
+ context, min_node_weight_t->NumElements() == 1,
+ errors::InvalidArgument("min_node_weight argument must be a scalar"));
const auto min_node_weight = min_node_weight_t->scalar()();
std::vector output_node_ids;
@@ -290,7 +357,7 @@ class BoostedTreesCalculateBestFeatureSplitOp : public OpKernel {
std::vector output_thresholds;
std::vector output_left_node_contribs;
std::vector output_right_node_contribs;
- std::vector output_split_types;
+ std::vector output_split_types;
// TODO(tanzheny) parallelize the computation.
// Iterate each node and find the best gain per node.
@@ -559,6 +626,9 @@ class BoostedTreesCalculateBestFeatureSplitV2 : public OpKernel {
explicit BoostedTreesCalculateBestFeatureSplitV2(
OpKernelConstruction* const context)
: OpKernel(context) {
+ VLOG(1) << "Boosted Trees kernels in TF are deprecated. Please use "
+ << "TensorFlow Decision Forests instead "
+ << "(https://github.com/tensorflow/decision-forests).\n";
OP_REQUIRES_OK(context, context->GetAttr("logits_dimension", &logits_dim_));
OP_REQUIRES_OK(context, context->GetAttr("num_features", &num_features_));
}
@@ -567,6 +637,20 @@ class BoostedTreesCalculateBestFeatureSplitV2 : public OpKernel {
// node_id_range
const Tensor* node_id_range_t;
OP_REQUIRES_OK(context, context->input("node_id_range", &node_id_range_t));
+ OP_REQUIRES(context, TensorShapeUtils::IsVector(node_id_range_t->shape()),
+ errors::InvalidArgument(
+ "node_id_range must be a vector, received shape ",
+ node_id_range_t->shape().DebugString()));
+ OP_REQUIRES(
+ context, node_id_range_t->dims() == 1,
+ errors::InvalidArgument("node_id_range must be a rank 1 tensor, but "
+ "given node_id_range has dims of ",
+ node_id_range_t->dims()));
+ OP_REQUIRES(context, node_id_range_t->dim_size(0) == 2,
+ errors::InvalidArgument(
+ "node_id_range must be a rank 1 tensor with shape=[2], but "
+ "given node_id_range has shape ",
+ node_id_range_t->dim_size(0), " on its first dim"));
const auto node_id_range = node_id_range_t->vec();
const int32 node_id_first = node_id_range(0); // Inclusive.
const int32 node_id_last = node_id_range(1); // Exclusive.
@@ -577,19 +661,30 @@ class BoostedTreesCalculateBestFeatureSplitV2 : public OpKernel {
&stats_summaries_list));
// Infer dimensions of a stats_summary.
- DCHECK_GT(stats_summaries_list.size(), 0);
+ OP_REQUIRES(
+ context, stats_summaries_list.size() >= 0,
+ errors::InvalidArgument("Got an empty list for stats_summaries_list"));
const int32 feature_dims = stats_summaries_list[0].dim_size(1);
// The last bucket is for default/missing value.
const int32 num_buckets = stats_summaries_list[0].dim_size(2) - 1;
const int32 logits_dim = logits_dim_;
const int32 hessian_dim = stats_summaries_list[0].dim_size(3) - logits_dim;
- DCHECK_GT(hessian_dim, 0);
- DCHECK_LE(hessian_dim, logits_dim * logits_dim);
+ OP_REQUIRES(context, hessian_dim > 0,
+ errors::InvalidArgument("hessian dim should be < 0, got ",
+ hessian_dim));
+ OP_REQUIRES(context, hessian_dim <= logits_dim * logits_dim,
+ errors::InvalidArgument(
+ "hessian dim should be <= ", logits_dim * logits_dim,
+ " but got: ", hessian_dim));
// Vector of stats_summaries; each element is stats for feature of shape
// [max_splits, feature_dim, num_buckets, logits_dim + hessian_dim].
std::vector::ConstTensor> stats_summaries;
- DCHECK_EQ(stats_summaries_list.size(), num_features_);
+ OP_REQUIRES(context, stats_summaries_list.size() == num_features_,
+ errors::InvalidArgument(
+ "Invalid stats_summaries_list size, got ",
+ stats_summaries_list.size(),
+ " but expected to match num_features ", num_features_));
stats_summaries.reserve(num_features_);
for (const auto& tensor : stats_summaries_list) {
stats_summaries.emplace_back(tensor.tensor());
@@ -598,8 +693,15 @@ class BoostedTreesCalculateBestFeatureSplitV2 : public OpKernel {
// Split types.
const Tensor* split_types_t;
OP_REQUIRES_OK(context, context->input("split_types", &split_types_t));
+ OP_REQUIRES(
+ context, TensorShapeUtils::IsVector(split_types_t->shape()),
+ errors::InvalidArgument("split_types must be a vector, received shape ",
+ split_types_t->shape().DebugString()));
const auto split_types = split_types_t->vec();
- DCHECK_EQ(split_types.size(), num_features_);
+ OP_REQUIRES(context, split_types.size() == num_features_,
+ errors::InvalidArgument(
+ "Invalid split_types size, got ", split_types.size(),
+ " but expected to match num_features ", num_features_));
// Validate.
for (int i = 0; i < num_features_; ++i) {
if (!(split_types(i) == kInequalitySplit ||
@@ -614,29 +716,59 @@ class BoostedTreesCalculateBestFeatureSplitV2 : public OpKernel {
const Tensor* candidate_feature_ids_t;
OP_REQUIRES_OK(context, context->input("candidate_feature_ids",
&candidate_feature_ids_t));
+ OP_REQUIRES(context,
+ TensorShapeUtils::IsVector(candidate_feature_ids_t->shape()),
+ errors::InvalidArgument(
+ "candidate_feature_ids must be a vector, received shape ",
+ candidate_feature_ids_t->shape().DebugString()));
const auto candidate_feature_ids = candidate_feature_ids_t->vec();
- DCHECK_EQ(candidate_feature_ids.size(), num_features_);
+ OP_REQUIRES(context, candidate_feature_ids.size() == num_features_,
+ errors::InvalidArgument(
+ "Invalid candidate_feature_ids size, got ",
+ candidate_feature_ids.size(),
+ " but expected to match num_features ", num_features_));
// L1, L2, tree_complexity, min_node_weight.
const Tensor* l1_t;
OP_REQUIRES_OK(context, context->input("l1", &l1_t));
+ OP_REQUIRES(
+ context, TensorShapeUtils::IsScalar(l1_t->shape()),
+ errors::InvalidArgument("l1 must be a scalar, got a tensor of shape ",
+ l1_t->shape().DebugString()));
const auto l1 = l1_t->scalar()();
- DCHECK_GE(l1, 0);
+ OP_REQUIRES(context, l1 >= 0,
+ errors::InvalidArgument("l1 = ", l1, " but it should be >= 0"));
if (logits_dim_ > 1) {
// Multi-class L1 regularization not supported yet.
- DCHECK_EQ(l1, 0);
+ OP_REQUIRES(
+ context, l1 == 0,
+ errors::InvalidArgument(
+ "l1 != 0 is not yet supported for multi-class regularization"));
}
const Tensor* l2_t;
OP_REQUIRES_OK(context, context->input("l2", &l2_t));
+ OP_REQUIRES(
+ context, TensorShapeUtils::IsScalar(l2_t->shape()),
+ errors::InvalidArgument("l2 must be a scalar, got a tensor of shape ",
+ l2_t->shape().DebugString()));
const auto l2 = l2_t->scalar