@@ -64,12 +64,15 @@ struct EValueConfig {
6464 EValueType type;
6565 std::vector<int32_t > tensor_sizes; // For Tensor type.
6666 std::vector<int32_t > tensor_list_items; // For TensorList type (indices).
67+ bool is_dynamic = false ; // For Tensor type: if true, uses DYNAMIC_BOUND.
6768};
6869
6970// Unified helper to create a minimal valid PTE flatbuffer with configurable
70- // evalues. Returns a buffer containing the flatbuffer data.
71+ // evalues. Returns a buffer containing the flatbuffer data. input_indices
72+ // specifies which value indices appear in the execution plan's inputs list.
7173std::vector<uint8_t > CreateTestProgram (
72- const std::vector<EValueConfig>& configs) {
74+ const std::vector<EValueConfig>& configs,
75+ const std::vector<int32_t >& input_indices = {}) {
7376 flatbuffers::FlatBufferBuilder builder (1024 );
7477
7578 std::vector<flatbuffers::Offset<executorch_flatbuffer::EValue>> evalues;
@@ -93,7 +96,9 @@ std::vector<uint8_t> CreateTestProgram(
9396 /* data_buffer_idx=*/ 0 ,
9497 /* allocation_info=*/ 0 ,
9598 /* layout=*/ 0 ,
96- executorch_flatbuffer::TensorShapeDynamism::STATIC ,
99+ config.is_dynamic
100+ ? executorch_flatbuffer::TensorShapeDynamism::DYNAMIC_BOUND
101+ : executorch_flatbuffer::TensorShapeDynamism::STATIC ,
97102 /* extra_tensor_info=*/ 0 );
98103 evalues.push_back (executorch_flatbuffer::CreateEValue (
99104 builder,
@@ -124,6 +129,7 @@ std::vector<uint8_t> CreateTestProgram(
124129
125130 auto values_vec = builder.CreateVector (evalues);
126131 auto plan_name = builder.CreateString (" forward" );
132+ auto inputs_vec = builder.CreateVector (input_indices);
127133 auto empty_int_vec = builder.CreateVector (std::vector<int32_t >{});
128134 auto empty_int64_vec = builder.CreateVector (std::vector<int64_t >{0 });
129135 auto empty_chain_vec = builder.CreateVector (
@@ -139,8 +145,8 @@ std::vector<uint8_t> CreateTestProgram(
139145 plan_name,
140146 /* container_meta_type=*/ 0 ,
141147 values_vec,
142- empty_int_vec ,
143- empty_int_vec,
148+ /* inputs= */ inputs_vec ,
149+ /* outputs= */ empty_int_vec,
144150 empty_chain_vec,
145151 empty_operators_vec,
146152 empty_delegates_vec,
@@ -206,29 +212,93 @@ TEST_F(ProgramValidationTest, InternalConsistencyDetectsTruncatedData) {
206212 ASSERT_EQ (program.error (), Error::InvalidProgram);
207213}
208214
209- // TEST_F(ProgramValidationTest, TensorNumelOverflowDetected) {
210- // std::vector<EValueConfig> configs = {
211- // {EValueType::Tensor, {2000000000, 2000000000, 2000000000}, {}}};
212- //
213- // AlignedBuffer buf(CreateTestProgram(configs));
214- // auto loader = buf.loader();
215- //
216- // Result<Program> program =
217- // Program::load(&loader, Program::Verification::InternalConsistency);
218- // EXPECT_EQ(program.error(), Error::InvalidProgram);
219- // }
220-
221- // TEST_F(ProgramValidationTest, TensorNumelOverflowNotDetectedWithMinimal) {
222- // std::vector<EValueConfig> configs = {
223- // {EValueType::Tensor, {2000000000, 2000000000, 2000000000}, {}}};
224- //
225- // AlignedBuffer buf(CreateTestProgram(configs));
226- // auto loader = buf.loader();
227- //
228- // // Minimal verification doesn't run program validation.
229- // Result<Program> program =
230- // Program::load(&loader, Program::Verification::Minimal);
231- // }
215+ TEST_F (ProgramValidationTest, TensorNumelOverflowDetectedForStaticTensor) {
216+ // Static tensors always have their overflow checked at validation time.
217+ std::vector<EValueConfig> configs = {
218+ {EValueType::Tensor,
219+ {2000000000 , 2000000000 , 2000000000 },
220+ {},
221+ /* is_dynamic=*/ false }};
222+
223+ AlignedBuffer buf (CreateTestProgram (configs));
224+ auto loader = buf.loader ();
225+
226+ Result<Program> program =
227+ Program::load (&loader, Program::Verification::InternalConsistency);
228+ EXPECT_EQ (program.error (), Error::InvalidProgram);
229+ }
230+
231+ TEST_F (ProgramValidationTest, TensorNumelOverflowNotDetectedWithMinimal) {
232+ std::vector<EValueConfig> configs = {
233+ {EValueType::Tensor,
234+ {2000000000 , 2000000000 , 2000000000 },
235+ {},
236+ /* is_dynamic=*/ false }};
237+
238+ AlignedBuffer buf (CreateTestProgram (configs));
239+ auto loader = buf.loader ();
240+
241+ // Minimal verification doesn't run program validation.
242+ Result<Program> program =
243+ Program::load (&loader, Program::Verification::Minimal);
244+ EXPECT_EQ (program.error (), Error::Ok);
245+ }
246+
247+ TEST_F (ProgramValidationTest, TensorNumelOverflowSkippedForDynamicInput) {
248+ // Dynamic input tensors skip overflow checks at validation time; the check
249+ // is deferred to set_input where actual sizes are known.
250+ std::vector<EValueConfig> configs = {
251+ {EValueType::Tensor,
252+ {2000000000 , 2000000000 , 2000000000 },
253+ {},
254+ /* is_dynamic=*/ true }};
255+
256+ // Mark value index 0 as a plan input.
257+ AlignedBuffer buf (CreateTestProgram (configs, /* input_indices=*/ {0 }));
258+ auto loader = buf.loader ();
259+
260+ Result<Program> program =
261+ Program::load (&loader, Program::Verification::InternalConsistency);
262+ EXPECT_EQ (program.error (), Error::Ok);
263+ }
264+
265+ TEST_F (
266+ ProgramValidationTest,
267+ TensorNumelOverflowDetectedForDynamicNonInputTensor) {
268+ // A dynamic tensor that is NOT in the inputs list should still have its
269+ // overflow checked at validation time.
270+ std::vector<EValueConfig> configs = {
271+ {EValueType::Tensor,
272+ {2000000000 , 2000000000 , 2000000000 },
273+ {},
274+ /* is_dynamic=*/ true }};
275+
276+ // No input indices — the tensor is not a plan input.
277+ AlignedBuffer buf (CreateTestProgram (configs));
278+ auto loader = buf.loader ();
279+
280+ Result<Program> program =
281+ Program::load (&loader, Program::Verification::InternalConsistency);
282+ EXPECT_EQ (program.error (), Error::InvalidProgram);
283+ }
284+
285+ TEST_F (ProgramValidationTest, TensorNumelOverflowDetectedForStaticInputTensor) {
286+ // A static input tensor should still have its overflow checked at
287+ // validation time since its sizes cannot change.
288+ std::vector<EValueConfig> configs = {
289+ {EValueType::Tensor,
290+ {2000000000 , 2000000000 , 2000000000 },
291+ {},
292+ /* is_dynamic=*/ false }};
293+
294+ // Mark value index 0 as a plan input.
295+ AlignedBuffer buf (CreateTestProgram (configs, /* input_indices=*/ {0 }));
296+ auto loader = buf.loader ();
297+
298+ Result<Program> program =
299+ Program::load (&loader, Program::Verification::InternalConsistency);
300+ EXPECT_EQ (program.error (), Error::InvalidProgram);
301+ }
232302
233303TEST_F (ProgramValidationTest, NegativeSizeDetected) {
234304 std::vector<EValueConfig> configs = {{EValueType::Tensor, {10 , -5 , 10 }, {}}};
0 commit comments