From f478d751f95cf63917611e1f9fadd6cd9bc19e25 Mon Sep 17 00:00:00 2001 From: Github Executorch Date: Tue, 21 Apr 2026 17:15:35 -0700 Subject: [PATCH] Update [ghstack-poisoned] --- runtime/executor/method.cpp | 26 ++++---- runtime/executor/tensor_parser.h | 6 +- runtime/executor/tensor_parser_exec_aten.cpp | 9 ++- runtime/executor/test/tensor_parser_test.cpp | 62 ++++++++++++++++++++ 4 files changed, 87 insertions(+), 16 deletions(-) diff --git a/runtime/executor/method.cpp b/runtime/executor/method.cpp index 1d3a940562e..028a5013fd3 100644 --- a/runtime/executor/method.cpp +++ b/runtime/executor/method.cpp @@ -210,10 +210,11 @@ class BackendDelegate final { } case executorch_flatbuffer::DataLocation::SEGMENT: { const char* backend_id = delegate.id()->c_str(); - return program->LoadSegment(DataLoader::SegmentInfo( - DataLoader::SegmentInfo::Type::Backend, - processed->index(), - backend_id)); + return program->LoadSegment( + DataLoader::SegmentInfo( + DataLoader::SegmentInfo::Type::Backend, + processed->index(), + backend_id)); } default: ET_LOG( @@ -492,9 +493,9 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { static_cast(val)->int_val()); } break; case executorch_flatbuffer::KernelTypes::Double: { - new (&values_[i]) - EValue(static_cast(val) - ->double_val()); + new (&values_[i]) EValue( + static_cast(val) + ->double_val()); } break; case executorch_flatbuffer::KernelTypes::Bool: { new (&values_[i]) EValue( @@ -1538,17 +1539,16 @@ Error Method::execute_instruction() { // We know that instr_args_as_FreeCall is non-null because it was checked // at init time. auto free_call = instruction->instr_args_as_FreeCall(); - auto& val = mutable_value(free_call->value_index()); - if (val.isTensor()) { - auto& t = val.toTensor(); - internal::reset_data_ptr(t); - } else { + auto t = mutable_value(free_call->value_index()).tryToTensor(); + if (!t.ok()) { ET_LOG( Error, "FreeCall target at index %u is not a Tensor", static_cast(free_call->value_index())); - err = Error::InvalidProgram; + err = t.error(); + break; } + internal::reset_data_ptr(t.get()); } break; default: ET_LOG( diff --git a/runtime/executor/tensor_parser.h b/runtime/executor/tensor_parser.h index fae183ea6e4..d4ab2ffe9a8 100644 --- a/runtime/executor/tensor_parser.h +++ b/runtime/executor/tensor_parser.h @@ -97,8 +97,12 @@ ET_NODISCARD Result>> parseListOptionalType( InvalidProgram, "Invalid value index %" PRId32 " for ListOptional", index); + auto optional_result = values[index].tryToOptional(); + if (!optional_result.ok()) { + return optional_result.error(); + } new (&optional_tensor_list[output_idx]) - std::optional(values[index].toOptional()); + std::optional(std::move(optional_result.get())); evalp_list[output_idx] = &values[static_cast(index)]; } output_idx++; diff --git a/runtime/executor/tensor_parser_exec_aten.cpp b/runtime/executor/tensor_parser_exec_aten.cpp index e73534bd0da..5267a089d60 100644 --- a/runtime/executor/tensor_parser_exec_aten.cpp +++ b/runtime/executor/tensor_parser_exec_aten.cpp @@ -98,10 +98,15 @@ ET_NODISCARD Result> parseTensorList( "Invalid value index %" PRId32 " for TensorList", tensor_index); + auto tensor_result = + values[static_cast(tensor_index)].tryToTensor(); + if (!tensor_result.ok()) { + return tensor_result.error(); + } // Placement new as the list elements are not initialized, so calling // copy assignment is not defined if it's non trivial. - new (&tensor_list[output_idx]) executorch::aten::Tensor( - values[static_cast(tensor_index)].toTensor()); + new (&tensor_list[output_idx]) + executorch::aten::Tensor(std::move(tensor_result.get())); evalp_list[output_idx] = &values[static_cast(tensor_index)]; output_idx++; } diff --git a/runtime/executor/test/tensor_parser_test.cpp b/runtime/executor/test/tensor_parser_test.cpp index df82c2f4e72..bf102d7d1f6 100644 --- a/runtime/executor/test/tensor_parser_test.cpp +++ b/runtime/executor/test/tensor_parser_test.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include #include @@ -19,6 +21,7 @@ using namespace ::testing; using executorch::aten::ScalarType; using executorch::aten::Tensor; +using executorch::runtime::BoxedEvalueList; using executorch::runtime::Error; using executorch::runtime::EValue; using executorch::runtime::FreeableBuffer; @@ -26,7 +29,9 @@ using executorch::runtime::Program; using executorch::runtime::Result; using executorch::runtime::Span; using executorch::runtime::TensorLayout; +using executorch::runtime::deserialization::parseListOptionalType; using executorch::runtime::deserialization::parseTensor; +using executorch::runtime::deserialization::parseTensorList; using executorch::runtime::deserialization::validateTensorLayout; using executorch::runtime::testing::ManagedMemoryManager; using torch::executor::util::FileDataLoader; @@ -223,3 +228,60 @@ TEST(ValidateTensorLayoutTest, DimOrderSizeMismatchIsRejected) { EXPECT_EQ( validateTensorLayout(s_tensor, layout.get()), Error::InvalidExternalData); } + +// Helper to construct a flatbuffers::Vector from raw data. +// FlatBuffer vectors are stored as [uint32_t length][T elements...]. +namespace { +struct FlatVectorInt32 { + static const flatbuffers::Vector* create( + std::vector& buf, + const std::vector& elements) { + buf.resize(sizeof(uint32_t) + elements.size() * sizeof(int32_t)); + uint32_t len = static_cast(elements.size()); + memcpy(buf.data(), &len, sizeof(len)); + if (!elements.empty()) { + memcpy( + buf.data() + sizeof(uint32_t), + elements.data(), + elements.size() * sizeof(int32_t)); + } + return reinterpret_cast*>(buf.data()); + } +}; +} // namespace + +// parseTensorList should return an error when the EValue at the given index +// is not a Tensor, instead of aborting. +TEST_F(TensorParserTest, ParseTensorListRejectsNonTensorEValue) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + + // Create an EValue array with a non-Tensor value at index 0. + EValue values[2]; + values[0] = EValue(static_cast(42)); // Int, not Tensor + values[1] = EValue(static_cast(7)); + + // Create a vector with index 0 (pointing to the Int EValue). + std::vector vec_buf; + auto* indices = FlatVectorInt32::create(vec_buf, {0}); + + auto result = parseTensorList(indices, values, 2, &mmm.get()); + EXPECT_EQ(result.error(), Error::InvalidType); +} + +// parseListOptionalType should return an error when the EValue at the given +// index is neither None nor the expected type. +TEST_F(TensorParserTest, ParseListOptionalTypeRejectsWrongType) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + + // Create an EValue array with a non-Tensor, non-None value at index 0. + EValue values[2]; + values[0] = EValue(static_cast(42)); // Int, not Tensor or None + values[1] = EValue(static_cast(7)); + + // Create a vector with index 0 (pointing to the Int EValue). + std::vector vec_buf; + auto* indices = FlatVectorInt32::create(vec_buf, {0}); + + auto result = parseListOptionalType(indices, values, 2, &mmm.get()); + EXPECT_EQ(result.error(), Error::InvalidType); +}