Skip to content

Commit 77222c1

Browse files
shoumikhinfacebook-github-bot
authored andcommitted
Require setting all inputs before execution. (#13207)
Summary: Pull Request resolved: #13207 Method never cared to check all the inputs were properly set before execution and basically used some default allocated memory for unset inputs. Here we introduce a safety check to guarantee users don't forget to set all inputs explicitly. Reviewed By: JacobSzwejbka Differential Revision: D79849134
1 parent 5336a06 commit 77222c1

File tree

8 files changed

+139
-28
lines changed

8 files changed

+139
-28
lines changed

extension/runner_util/test/inputs_test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ class InputsTest : public ::testing::Test {
7575
TEST_F(InputsTest, Smoke) {
7676
Result<BufferCleanup> input_buffers = prepare_input_tensors(*method_);
7777
ASSERT_EQ(input_buffers.error(), Error::Ok);
78+
auto input_err = method_->set_input(executorch::runtime::EValue(1.0), 2);
79+
ASSERT_EQ(input_err, Error::Ok);
7880

7981
// We can't look at the input tensors, but we can check that the outputs make
8082
// sense after executing the method.

runtime/executor/method.cpp

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -407,11 +407,22 @@ Error Method::parse_values(const NamedDataMap* external_data_map) {
407407
auto flatbuffer_values = serialization_plan_->values();
408408
ET_CHECK_OR_RETURN_ERROR(
409409
flatbuffer_values != nullptr, InvalidProgram, "Missing values");
410-
size_t n_value = flatbuffer_values->size();
410+
const size_t n_value = flatbuffer_values->size();
411411
values_ = memory_manager_->method_allocator()->allocateList<EValue>(n_value);
412412
if (values_ == nullptr) {
413413
return Error::MemoryAllocationFailed;
414414
}
415+
const size_t n_input = inputs_size();
416+
if (n_input > 0) {
417+
input_set_ =
418+
memory_manager_->method_allocator()->allocateList<bool>(n_input);
419+
if (input_set_ == nullptr) {
420+
return Error::MemoryAllocationFailed;
421+
}
422+
for (size_t i = 0; i < n_input; ++i) {
423+
input_set_[i] = false;
424+
}
425+
}
415426

416427
// Count the number of tensors marked as EXTERNAL for this method. The actual
417428
// number of external constants may be smaller, eg. if multiple tensors point
@@ -1159,31 +1170,15 @@ Method::set_input(const EValue& input_evalue, size_t input_idx) {
11591170

11601171
return Error::InvalidArgument;
11611172
}
1173+
input_set_[input_idx] = true;
1174+
11621175
return Error::Ok;
11631176
}
11641177

11651178
ET_NODISCARD Error
11661179
Method::set_inputs(const executorch::aten::ArrayRef<EValue>& input_evalues) {
1167-
ET_CHECK_OR_RETURN_ERROR(
1168-
initialized(),
1169-
InvalidState,
1170-
"Inputs can not be set until method has been initialized.");
1171-
1172-
ET_CHECK_OR_RETURN_ERROR(
1173-
step_state_.instr_idx == 0 && step_state_.chain_idx == 0,
1174-
InvalidState,
1175-
"Inputs can not be set mid execution.");
1176-
1177-
size_t input_size = inputs_size();
1178-
ET_CHECK_OR_RETURN_ERROR(
1179-
input_size == input_evalues.size(),
1180-
InvalidArgument,
1181-
"The length of given input array (%" ET_PRIsize_t
1182-
") must be same as the number of inputs in method (%" ET_PRIsize_t ").",
1183-
input_evalues.size(),
1184-
input_size);
1185-
1186-
for (size_t i = 0; i < input_size; i++) {
1180+
const size_t n_input = inputs_size();
1181+
for (size_t i = 0; i < n_input; ++i) {
11871182
ET_CHECK_OK_OR_RETURN_ERROR(set_input(input_evalues[i], i));
11881183
}
11891184
return Error::Ok;
@@ -1277,20 +1272,18 @@ ET_NODISCARD Error Method::get_inputs(EValue* input_evalues, size_t length) {
12771272
initialized(),
12781273
InvalidState,
12791274
"Inputs can not be retrieved until method has been initialized.");
1280-
1275+
const size_t n_input = inputs_size();
12811276
ET_CHECK_OR_RETURN_ERROR(
1282-
length >= inputs_size(),
1277+
length >= n_input,
12831278
InvalidArgument,
12841279
"The given array is not large enough to hold all inputs.");
12851280

1286-
for (size_t i = 0; i < inputs_size(); i++) {
1281+
for (size_t i = 0; i < n_input; ++i) {
12871282
input_evalues[i] = values_[get_input_index(i)];
12881283
}
1289-
1290-
for (size_t i = inputs_size(); i < length; i++) {
1284+
for (size_t i = n_input; i < length; ++i) {
12911285
input_evalues[i] = EValue();
12921286
}
1293-
12941287
return Error::Ok;
12951288
}
12961289

@@ -1538,6 +1531,14 @@ Error Method::execute() {
15381531
initialized(),
15391532
NotSupported,
15401533
"Cannot execute until method has been initialized.");
1534+
const size_t n_input = inputs_size();
1535+
for (size_t i = 0; i < n_input; ++i) {
1536+
ET_CHECK_OR_RETURN_ERROR(
1537+
input_set_[i],
1538+
InvalidArgument,
1539+
"Input %" ET_PRIsize_t " has not been set.",
1540+
i);
1541+
}
15411542
ET_LOG(Debug, "Executing method: %s.", method_meta().name());
15421543

15431544
// Chains are executed sequentially today, but future async designs may

runtime/executor/method.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class Method final {
7373
event_tracer_(rhs.event_tracer_),
7474
n_value_(rhs.n_value_),
7575
values_(rhs.values_),
76+
input_set_(rhs.input_set_),
7677
n_delegate_(rhs.n_delegate_),
7778
delegates_(rhs.delegates_),
7879
n_chains_(rhs.n_chains_),
@@ -85,6 +86,7 @@ class Method final {
8586
// anything twice.
8687
rhs.n_value_ = 0;
8788
rhs.values_ = nullptr;
89+
rhs.input_set_ = nullptr;
8890
rhs.n_delegate_ = 0;
8991
rhs.delegates_ = nullptr;
9092

@@ -314,6 +316,7 @@ class Method final {
314316
event_tracer_(event_tracer),
315317
n_value_(0),
316318
values_(nullptr),
319+
input_set_(nullptr),
317320
n_delegate_(0),
318321
delegates_(nullptr),
319322
n_chains_(0),
@@ -362,6 +365,7 @@ class Method final {
362365

363366
size_t n_value_;
364367
EValue* values_;
368+
bool* input_set_;
365369

366370
size_t n_delegate_;
367371
BackendDelegate* delegates_;

runtime/executor/test/allocation_failure_stress_test.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ TEST_F(AllocationFailureStressTest, End2EndIncreaseRuntimeMemUntilSuccess) {
8888
// once load was successful.
8989
auto input_cleanup = prepare_input_tensors(*method);
9090
ASSERT_EQ(input_cleanup.error(), Error::Ok);
91+
auto input_err = method->set_input(executorch::runtime::EValue(1.0), 2);
92+
ASSERT_EQ(input_err, Error::Ok);
9193
err = method->execute();
9294
ASSERT_EQ(err, Error::Ok);
9395
}
@@ -123,6 +125,8 @@ TEST_F(AllocationFailureStressTest, End2EndNonConstantMemUntilSuccess) {
123125
// once load was successful.
124126
auto input_cleanup = prepare_input_tensors(*method);
125127
ASSERT_EQ(input_cleanup.error(), Error::Ok);
128+
auto input_err = method->set_input(executorch::runtime::EValue(1.0), 2);
129+
ASSERT_EQ(input_err, Error::Ok);
126130
err = method->execute();
127131
ASSERT_EQ(err, Error::Ok);
128132
}

runtime/executor/test/backend_data_separation_test.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,21 @@ TEST_F(BackendDataSeparationTest, TestSeparation) {
9595
/*named_data_map=*/linear_data_map_.get());
9696
ASSERT_EQ(method.error(), Error::Ok);
9797

98+
// Set a dummy input.
99+
int32_t sizes[1] = {3};
100+
uint8_t dim_order[1] = {0};
101+
int32_t strides[1] = {1};
102+
executorch::aten::TensorImpl impl(
103+
executorch::aten::ScalarType::Float,
104+
1,
105+
sizes,
106+
nullptr,
107+
dim_order,
108+
strides);
109+
auto input_err = method->set_input(
110+
executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
111+
ASSERT_EQ(input_err, Error::Ok);
112+
98113
// Can execute the method.
99114
Error err = method->execute();
100115
ASSERT_EQ(err, Error::Ok);

runtime/executor/test/backend_integration_test.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,25 @@ TEST_P(BackendIntegrationTest, GetMethodNameDuringExecuteSuccess) {
603603
ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes);
604604
Result<Method> method = program->load_method("forward", &mmm.get());
605605
EXPECT_TRUE(method.ok());
606+
607+
int32_t sizes[2] = {2, 2};
608+
uint8_t dim_order[2] = {0, 1};
609+
int32_t strides[2] = {2, 1};
610+
executorch::aten::TensorImpl impl(
611+
executorch::aten::ScalarType::Float,
612+
2,
613+
sizes,
614+
nullptr,
615+
dim_order,
616+
strides);
617+
auto input_err = method->set_input(
618+
executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
619+
input_err = method->set_input(
620+
executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 1);
621+
input_err = method->set_input(
622+
executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 2);
623+
ASSERT_EQ(input_err, Error::Ok);
624+
606625
Error err = method->execute();
607626
ASSERT_EQ(err, Error::Ok);
608627
}

runtime/executor/test/kernel_integration_test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ class KernelIntegrationTest : public ::testing::Test {
248248
ASSERT_EQ(inputs_cleanup.error(), Error::Ok);
249249
inputs_cleanup_ = std::make_unique<executorch::extension::BufferCleanup>(
250250
std::move(*inputs_cleanup));
251+
auto input_err = method_->set_input(executorch::runtime::EValue(1.0), 2);
252+
ASSERT_EQ(input_err, Error::Ok);
251253
}
252254

253255
void TearDown() override {

runtime/executor/test/method_test.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,13 @@ TEST_F(MethodTest, MoveTest) {
104104
Result<Method> method = programs_["add"]->load_method("forward", &mmm.get());
105105
ASSERT_EQ(method.error(), Error::Ok);
106106

107-
// Can execute the method.
107+
// Set dummy inputs.
108108
auto input_cleanup = prepare_input_tensors(*method);
109109
ASSERT_EQ(input_cleanup.error(), Error::Ok);
110+
auto input_err = method->set_input(executorch::runtime::EValue(1.0), 2);
111+
ASSERT_EQ(input_err, Error::Ok);
112+
113+
// Can execute the method.
110114
Error err = method->execute();
111115
ASSERT_EQ(err, Error::Ok);
112116

@@ -312,6 +316,21 @@ TEST_F(MethodTest, ConstantSegmentTest) {
312316
programs_["add_mul"]->load_method("forward", &mmm.get());
313317
ASSERT_EQ(method.error(), Error::Ok);
314318

319+
// Set a dummy input.
320+
int32_t sizes[2] = {2, 2};
321+
uint8_t dim_order[2] = {0, 1};
322+
int32_t strides[2] = {2, 1};
323+
executorch::aten::TensorImpl impl(
324+
executorch::aten::ScalarType::Float,
325+
2,
326+
sizes,
327+
nullptr,
328+
dim_order,
329+
strides);
330+
auto input_err = method->set_input(
331+
executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
332+
ASSERT_EQ(input_err, Error::Ok);
333+
315334
// Can execute the method.
316335
Error err = method->execute();
317336
ASSERT_EQ(err, Error::Ok);
@@ -324,6 +343,21 @@ TEST_F(MethodTest, ConstantBufferTest) {
324343
programs_["linear_constant_buffer"]->load_method("forward", &mmm.get());
325344
ASSERT_EQ(method.error(), Error::Ok);
326345

346+
// Set a dummy input.
347+
int32_t sizes[2] = {2, 2};
348+
uint8_t dim_order[2] = {0, 1};
349+
int32_t strides[2] = {2, 1};
350+
executorch::aten::TensorImpl impl(
351+
executorch::aten::ScalarType::Float,
352+
2,
353+
sizes,
354+
nullptr,
355+
dim_order,
356+
strides);
357+
auto input_err = method->set_input(
358+
executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
359+
ASSERT_EQ(input_err, Error::Ok);
360+
327361
// Can execute the method.
328362
Error err = method->execute();
329363
ASSERT_EQ(err, Error::Ok);
@@ -335,6 +369,21 @@ TEST_F(MethodTest, ProgramDataSeparationTest) {
335369
"forward", &mmm.get(), nullptr, data_maps_["add_mul_data"].get());
336370
ASSERT_EQ(method.error(), Error::Ok);
337371

372+
// Set a dummy input.
373+
int32_t sizes[2] = {2, 2};
374+
uint8_t dim_order[2] = {0, 1};
375+
int32_t strides[2] = {2, 1};
376+
executorch::aten::TensorImpl impl(
377+
executorch::aten::ScalarType::Float,
378+
2,
379+
sizes,
380+
nullptr,
381+
dim_order,
382+
strides);
383+
auto input_err = method->set_input(
384+
executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
385+
ASSERT_EQ(input_err, Error::Ok);
386+
338387
// Can execute the method.
339388
Error err = method->execute();
340389
ASSERT_EQ(err, Error::Ok);
@@ -357,6 +406,21 @@ TEST_F(MethodTest, MethodGetAttributeTest) {
357406
// expect data to be set
358407
EXPECT_EQ(res->const_data_ptr(), &data);
359408

409+
// Set a dummy input.
410+
int32_t sizes[1] = {1};
411+
uint8_t dim_order[1] = {0};
412+
int32_t strides[1] = {1};
413+
executorch::aten::TensorImpl impl(
414+
executorch::aten::ScalarType::Float,
415+
1,
416+
sizes,
417+
nullptr,
418+
dim_order,
419+
strides);
420+
auto input_err = method->set_input(
421+
executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
422+
ASSERT_EQ(input_err, Error::Ok);
423+
360424
// Can execute the method.
361425
Error err = method->execute();
362426
ASSERT_EQ(err, Error::Ok);

0 commit comments

Comments
 (0)