Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions extension/aten_util/aten_bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,22 @@ namespace extension {

namespace {
void check_tensor_meta(const at::Tensor& a, const executorch::aten::Tensor& b) {
// Check sizes/strides pointers
ET_CHECK_MSG(
b.sizes().data() != nullptr, "ETensor must have valid sizes array");
ET_CHECK_MSG(
b.strides().data() != nullptr, "ETensor must have valid strides array");
// 0-dim (scalar) tensors legitimately have empty sizes/strides arrays;
// their `.data()` may return nullptr depending on the underlying container.
// Only require non-null sizes/strides/dim_order storage when the tensor
// actually has at least one dimension. The nullptr check is meant to catch
// malformed metadata for ranked tensors (where these arrays MUST be
// addressable because dim_order_to_stride_nocheck below indexes into them);
// it must not abort on valid 0-dim inputs.
if (b.dim() > 0) {
ET_CHECK_MSG(
b.sizes().data() != nullptr, "ETensor must have valid sizes array");
ET_CHECK_MSG(
b.strides().data() != nullptr, "ETensor must have valid strides array");
ET_CHECK_MSG(
b.dim_order().data() != nullptr,
"ETensor must have valid dim_order array");
}
// Check disabled because in ASR model we get 1 element tensor with different
// rank.
/*
Expand Down
41 changes: 41 additions & 0 deletions extension/aten_util/test/aten_bridge_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,47 @@ TEST(ATenBridgeTest, AliasTensorPtrToATenTensor) {
EXPECT_EQ(at_tensor.const_data_ptr(), et_tensor_ptr->const_data_ptr());
}

// 0-dim (scalar) tensors legitimately have empty sizes/strides arrays whose
// `.data()` may return nullptr. Regression test for T270603238: ensure
// check_tensor_meta does not abort on valid 0-dim tensors. We pass nullptr
// explicitly for sizes/dim_order/strides because std::vector::data() on an
// empty vector is implementation-defined (libstdc++/libc++ may return a
// non-null sentinel) — using nullptr makes the regression deterministic
// across STL implementations.
TEST(ATenBridgeTest, AliasETensorToATenTensorZeroDim) {
auto at_tensor = at::scalar_tensor(42.0f);
ASSERT_EQ(at_tensor.dim(), 0);
auto dtype = torchToExecuTorchScalarType(at_tensor.options().dtype());
torch::executor::TensorImpl tensor_impl(
dtype,
/*dim=*/0,
/*sizes=*/nullptr,
/*data=*/nullptr,
/*dim_order=*/nullptr,
/*strides=*/nullptr);
torch::executor::Tensor etensor(&tensor_impl);
alias_etensor_to_attensor(at_tensor, etensor);
EXPECT_EQ(at_tensor.const_data_ptr(), etensor.const_data_ptr());
}

TEST(ATenBridgeTest, AliasATTensorToETensorZeroDim) {
auto at_tensor = at::scalar_tensor(7);
ASSERT_EQ(at_tensor.dim(), 0);
auto dtype = torchToExecuTorchScalarType(at_tensor.options().dtype());
std::vector<uint8_t> etensor_data(at_tensor.nbytes());
torch::executor::TensorImpl tensor_impl(
dtype,
/*dim=*/0,
/*sizes=*/nullptr,
etensor_data.data(),
/*dim_order=*/nullptr,
/*strides=*/nullptr);
torch::executor::Tensor etensor(&tensor_impl);
auto aliased_at_tensor = alias_attensor_to_etensor(etensor);
EXPECT_EQ(aliased_at_tensor.dim(), 0);
EXPECT_EQ(aliased_at_tensor.const_data_ptr(), etensor_data.data());
}

TEST(ATenBridgeTest, AliasATTensorToETensorChannelsLast) {
auto at_tensor = at::randn({2, 3, 4, 5}).to(at::MemoryFormat::ChannelsLast);
std::vector<Tensor::SizesType> sizes(
Expand Down
Loading