You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a6fe4b4
Browse filesBrowse the repository at this point in the historyBrowse files
Add validate_tensor_layout to check a layout without aborting
make_tensor_ptr checks sizes, dim order and strides with ET_CHECK, so an
invalid layout aborts the process:
std::vector<float> data(16);
auto t = make_tensor_ptr({2, 2}, data.data(), {}, {8, 2});
// invalid strides for dim 0: 8!= 2 while its size is 2 != 1
That is fine for a layout the program builds itself. But a program that gets
the layout from outside, for example from a file or over the network, has no
ExecuTorch function to reject a bad one and keep running. ExecuTorch has no
exceptions, so it needs a check that returns an Error. (PyTorch accepts these
strides, because its tensors do not have to be dense.)
Add validate_tensor_layout(sizes, dim_order, strides). It returns
Error::InvalidArgument for every layout that the make_tensor_ptr overloads
taking sizes and data abort on, and also for sizes that are negative or whose
product overflows:
if (validate_tensor_layout(sizes, {}, strides) != Error::Ok) {
return Error::InvalidArgument;
}
It does not look at the data, so the caller still has to check that the data
size matches the sizes. The tensor guide shows both checks.
The layout checks move into one internal function that make_tensor_ptr and
validate_tensor_layout both call. It also computes the strides with an
overflow check. Before, a stride that does not fit StridesType was computed
with signed overflow, which is undefined behavior. For example, in portable
mode make_tensor_ptr({0, 65536, 65536}, std::vector<float>{}) built a tensor
with strides {0, 65536, 1}. Such a layout now aborts make_tensor_ptr, the way
PyTorch throws "Stride calculation overflowed" when its own strides overflow.
In portable mode this also covers layouts that used to pass even though a
stride overflowed:
- On 64-bit targets, every layout whose element count overflows. The raw
pointer overload accepted these with a wrong element count.
- Tensors with data whose only stride that does not fit belongs to a size-1
dim, which is never used to address the data. For example, make_tensor_ptr
with sizes {1, 16384, 131072} (2^31 elements), or a clone of such a tensor,
now aborts, while sizes {16384, 131072} with the same data still work.
Every other layout is accepted or rejected as before. Only the abort message
changes, to "Invalid tensor layout.", with the reason logged on the line
before it.
The WebAssembly bindings kept their own copy of these checks, so that
Tensor.fromArray and Tensor.fromIter throw a JS error instead of aborting.
They now call validate_tensor_layout, so an empty tensor whose strides
overflow, such as sizes [0, 65536, 65536], now throws instead of being built.
All their layout errors now throw "Invalid tensor layout.", also for negative
or overflowing sizes, which used to throw
"Invalid tensor sizes: numel computation failed". The reason is logged only
in builds with logging enabled, which in CMake are Debug builds by default.
Copy file name to clipboardExpand all lines: docs/source/extension-tensor.md
+19Lines changed: 19 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -160,6 +160,25 @@ auto tensor = make_tensor_ptr(
160
160
161
161
The `TensorPtr` will call the custom deleter when it is destroyed, i.e., when the smart pointer is reset and no more references to the underlying `Tensor` exist.
162
162
163
+
#### Checking a Layout Without Aborting
164
+
165
+
`make_tensor_ptr` aborts the process if the sizes, dim order and strides do not describe a valid layout, or if the data does not match the sizes. When they come from outside the program, for example from a file or over the network, check them first:
166
+
167
+
```cpp
168
+
if (validate_tensor_layout(sizes, dim_order, strides) != Error::Ok) {
169
+
return Error::InvalidArgument; // reject the input instead of aborting
170
+
}
171
+
// After the check above, this product cannot overflow.
auto tensor = make_tensor_ptr(sizes, std::move(data), dim_order, strides);
178
+
```
179
+
180
+
`validate_tensor_layout` does not look at the data, so check its size yourself, as above. For a `std::vector<uint8_t>` of raw bytes, the expected size is `numel * elementSize(type)` bytes. Compute it with an overflow check, because this product can overflow `size_t` even when `numel` fits.
181
+
163
182
#### Sharing Existing Tensor
164
183
165
184
Since `TensorPtr` is a `std::shared_ptr<Tensor>`, you can easily create a `TensorPtr` that shares an existing `Tensor`. Any changes made to the shared data are reflected across all instances sharing the same data.
0 commit comments