Skip to content

Commit 358b4e2

Browse files
psiddhfacebook-github-bot
authored andcommitted
Fix VGF runtime aborts on 0-dim tensor inputs and Python scalar coercion (#19446)
Summary: The ARM-backend VGF tests (e.g. ``test_sum_dim_intlist_vgf_quant`` and ``test_sum_dim_intlist_vgf_no_quant`` for all 19 parametrizations) were hard-aborting the pytest process with two latent bugs that compounded: 1. **C++ aten_bridge nullptr assert on 0-dim tensors (T270603238).** ``executorch/extension/aten_util/aten_bridge.cpp::check_tensor_meta`` had two unconditional ``ET_CHECK_MSG(b.{sizes,strides}().data() != nullptr, ...)`` asserts. For 0-dim (scalar) tensors, ``sizes()``/``strides()`` are empty ``IntArrayRef``s whose ``.data()`` may legitimately return nullptr. The process aborted on every valid scalar tensor input. Fix: gate the nullptr checks on ``b.dim() > 0``. The subsequent loops are no-ops when ``dim() == 0`` and ``dim_order_to_stride_nocheck`` already early-returns for ``dims == 0`` (``dim_order_util.h:132-134``), so the relaxed asserts are safe. 2. **VGF Python runner over-wrapping non-tensor inputs (Error::InvalidArgument 0x12).** ``runner_fb.run_vgf`` previously called ``torch.tensor(x)`` on every non-tensor input (including ``None``/``bool``/``int``), producing 0-dim tensors. The lowered method's signature, however, expects ``EValue`` tags ``Int``/``Bool``/``None`` for those slots — receiving a ``Tensor`` caused ``Method::set_inputs`` to reject the inputs. The pybindings layer (``pybindings.cpp:804-809``) already natively handles ``None``/``bool``/``int`` Python objects; the runner just had to stop interfering. Fix: only wrap Python ``float`` (and other unknown types) as 0-dim tensors — the original ``addmm`` alpha/beta motivation. Pass ``None``/``bool``/``int`` through unchanged. 3. **Regression tests** for the C++ fix in ``executorch/extension/aten_util/test/aten_bridge_test.cpp``: ``AliasETensorToATenTensorZeroDim`` and ``AliasATTensorToETensorZeroDim`` construct true 0-dim tensors via ``at::scalar_tensor`` and verify the bridge does not abort. The existing ``AliasETensorToATenTensorFail`` death test still fires for ranked tensors with empty strides because that case has ``dim() == 3 > 0``. Fixes T270603238. Differential Revision: D104603739
1 parent a49171d commit 358b4e2

2 files changed

Lines changed: 57 additions & 5 deletions

File tree

extension/aten_util/aten_bridge.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,22 @@ namespace extension {
1818

1919
namespace {
2020
void check_tensor_meta(const at::Tensor& a, const executorch::aten::Tensor& b) {
21-
// Check sizes/strides pointers
22-
ET_CHECK_MSG(
23-
b.sizes().data() != nullptr, "ETensor must have valid sizes array");
24-
ET_CHECK_MSG(
25-
b.strides().data() != nullptr, "ETensor must have valid strides array");
21+
// 0-dim (scalar) tensors legitimately have empty sizes/strides arrays;
22+
// their `.data()` may return nullptr depending on the underlying container.
23+
// Only require non-null sizes/strides/dim_order storage when the tensor
24+
// actually has at least one dimension. The nullptr check is meant to catch
25+
// malformed metadata for ranked tensors (where these arrays MUST be
26+
// addressable because dim_order_to_stride_nocheck below indexes into them);
27+
// it must not abort on valid 0-dim inputs.
28+
if (b.dim() > 0) {
29+
ET_CHECK_MSG(
30+
b.sizes().data() != nullptr, "ETensor must have valid sizes array");
31+
ET_CHECK_MSG(
32+
b.strides().data() != nullptr, "ETensor must have valid strides array");
33+
ET_CHECK_MSG(
34+
b.dim_order().data() != nullptr,
35+
"ETensor must have valid dim_order array");
36+
}
2637
// Check disabled because in ASR model we get 1 element tensor with different
2738
// rank.
2839
/*

extension/aten_util/test/aten_bridge_test.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,47 @@ TEST(ATenBridgeTest, AliasTensorPtrToATenTensor) {
155155
EXPECT_EQ(at_tensor.const_data_ptr(), et_tensor_ptr->const_data_ptr());
156156
}
157157

158+
// 0-dim (scalar) tensors legitimately have empty sizes/strides arrays whose
159+
// `.data()` may return nullptr. Regression test for T270603238: ensure
160+
// check_tensor_meta does not abort on valid 0-dim tensors. We pass nullptr
161+
// explicitly for sizes/dim_order/strides because std::vector::data() on an
162+
// empty vector is implementation-defined (libstdc++/libc++ may return a
163+
// non-null sentinel) — using nullptr makes the regression deterministic
164+
// across STL implementations.
165+
TEST(ATenBridgeTest, AliasETensorToATenTensorZeroDim) {
166+
auto at_tensor = at::scalar_tensor(42.0f);
167+
ASSERT_EQ(at_tensor.dim(), 0);
168+
auto dtype = torchToExecuTorchScalarType(at_tensor.options().dtype());
169+
torch::executor::TensorImpl tensor_impl(
170+
dtype,
171+
/*dim=*/0,
172+
/*sizes=*/nullptr,
173+
/*data=*/nullptr,
174+
/*dim_order=*/nullptr,
175+
/*strides=*/nullptr);
176+
torch::executor::Tensor etensor(&tensor_impl);
177+
alias_etensor_to_attensor(at_tensor, etensor);
178+
EXPECT_EQ(at_tensor.const_data_ptr(), etensor.const_data_ptr());
179+
}
180+
181+
TEST(ATenBridgeTest, AliasATTensorToETensorZeroDim) {
182+
auto at_tensor = at::scalar_tensor(7);
183+
ASSERT_EQ(at_tensor.dim(), 0);
184+
auto dtype = torchToExecuTorchScalarType(at_tensor.options().dtype());
185+
std::vector<uint8_t> etensor_data(at_tensor.nbytes());
186+
torch::executor::TensorImpl tensor_impl(
187+
dtype,
188+
/*dim=*/0,
189+
/*sizes=*/nullptr,
190+
etensor_data.data(),
191+
/*dim_order=*/nullptr,
192+
/*strides=*/nullptr);
193+
torch::executor::Tensor etensor(&tensor_impl);
194+
auto aliased_at_tensor = alias_attensor_to_etensor(etensor);
195+
EXPECT_EQ(aliased_at_tensor.dim(), 0);
196+
EXPECT_EQ(aliased_at_tensor.const_data_ptr(), etensor_data.data());
197+
}
198+
158199
TEST(ATenBridgeTest, AliasATTensorToETensorChannelsLast) {
159200
auto at_tensor = at::randn({2, 3, 4, 5}).to(at::MemoryFormat::ChannelsLast);
160201
std::vector<Tensor::SizesType> sizes(

0 commit comments

Comments
 (0)