@@ -618,3 +618,165 @@ TEST_F(ProgramTest, LoadAndCheckPTESize) {
618618 Result<Program> truncated_program = Program::load (&truncated_loader);
619619 ASSERT_EQ (truncated_program.error (), Error::InvalidProgram);
620620}
621+
622+ // Regression test for null pointer dereference in
623+ // get_output_flattening_encoding when container_meta_type is missing from the
624+ // ExecutionPlan.
625+ TEST_F (ProgramTest, GetOutputFlatteningEncodingWithMissingContainerMetaType) {
626+ // Build a minimal valid Program with an ExecutionPlan that has NO
627+ // container_meta_type. This would previously crash with a null pointer
628+ // dereference.
629+ flatbuffers::FlatBufferBuilder builder (1024 );
630+
631+ // Create a minimal ExecutionPlan with name but NO container_meta_type
632+ auto plan_name = builder.CreateString (" forward" );
633+
634+ // Create empty vectors for required fields
635+ auto empty_values = builder.CreateVector (
636+ std::vector<flatbuffers::Offset<executorch_flatbuffer::EValue>>{});
637+ auto empty_inputs = builder.CreateVector (std::vector<int32_t >{});
638+ auto empty_outputs = builder.CreateVector (std::vector<int32_t >{});
639+ auto empty_chains = builder.CreateVector (
640+ std::vector<flatbuffers::Offset<executorch_flatbuffer::Chain>>{});
641+ auto empty_operators = builder.CreateVector (
642+ std::vector<flatbuffers::Offset<executorch_flatbuffer::Operator>>{});
643+ auto empty_delegates = builder.CreateVector (
644+ std::vector<
645+ flatbuffers::Offset<executorch_flatbuffer::BackendDelegate>>{});
646+ auto buffer_sizes = builder.CreateVector (std::vector<int64_t >{0 });
647+
648+ // Build ExecutionPlan WITHOUT container_meta_type (it will be null)
649+ auto execution_plan = executorch_flatbuffer::CreateExecutionPlan (
650+ builder,
651+ plan_name,
652+ 0 , // container_meta_type = null (this is the vulnerability trigger)
653+ empty_values,
654+ empty_inputs,
655+ empty_outputs,
656+ empty_chains,
657+ empty_operators,
658+ empty_delegates,
659+ buffer_sizes);
660+
661+ auto execution_plans = builder.CreateVector (
662+ std::vector<flatbuffers::Offset<executorch_flatbuffer::ExecutionPlan>>{
663+ execution_plan});
664+
665+ // Create empty segment info
666+ auto empty_constant_buffer = builder.CreateVector (
667+ std::vector<flatbuffers::Offset<executorch_flatbuffer::Buffer>>{});
668+ auto empty_backend_data = builder.CreateVector (
669+ std::vector<flatbuffers::Offset<
670+ executorch_flatbuffer::BackendDelegateInlineData>>{});
671+ auto empty_segments = builder.CreateVector (
672+ std::vector<flatbuffers::Offset<executorch_flatbuffer::DataSegment>>{});
673+
674+ // Build the Program
675+ auto program = executorch_flatbuffer::CreateProgram (
676+ builder,
677+ 0 , // version
678+ execution_plans,
679+ empty_constant_buffer,
680+ empty_backend_data,
681+ empty_segments);
682+
683+ builder.Finish (program, executorch_flatbuffer::ProgramIdentifier ());
684+
685+ // Copy to 16-byte aligned buffer (required by Program::load)
686+ alignas (16 ) uint8_t aligned_buffer[2048 ];
687+ ASSERT_LE (builder.GetSize (), sizeof (aligned_buffer));
688+ std::memcpy (aligned_buffer, builder.GetBufferPointer (), builder.GetSize ());
689+
690+ // Load the malformed program
691+ BufferDataLoader data_loader (aligned_buffer, builder.GetSize ());
692+ Result<Program> loaded_program =
693+ Program::load (&data_loader, Program::Verification::Minimal);
694+
695+ // Program should load successfully (the malformed data is valid FlatBuffer)
696+ ASSERT_EQ (loaded_program.error (), Error::Ok);
697+
698+ // Calling get_output_flattening_encoding should return an error,
699+ // NOT crash with null pointer dereference
700+ Result<const char *> encoding =
701+ loaded_program->get_output_flattening_encoding (" forward" );
702+
703+ // Should return InvalidProgram error due to missing container_meta_type
704+ EXPECT_EQ (encoding.error (), Error::InvalidProgram);
705+ }
706+
707+ // Test that get_output_flattening_encoding handles missing encoded_out_str
708+ TEST_F (ProgramTest, GetOutputFlatteningEncodingWithMissingEncodedOutStr) {
709+ flatbuffers::FlatBufferBuilder builder (2048 );
710+
711+ // Create ContainerMetadata with encoded_inp_str but NO encoded_out_str
712+ auto inp_str = builder.CreateString (" test_input" );
713+ auto container_meta = executorch_flatbuffer::CreateContainerMetadata (
714+ builder,
715+ inp_str,
716+ 0 ); // encoded_out_str = null
717+
718+ auto plan_name = builder.CreateString (" forward" );
719+ auto empty_values = builder.CreateVector (
720+ std::vector<flatbuffers::Offset<executorch_flatbuffer::EValue>>{});
721+ auto empty_inputs = builder.CreateVector (std::vector<int32_t >{});
722+ auto empty_outputs = builder.CreateVector (std::vector<int32_t >{});
723+ auto empty_chains = builder.CreateVector (
724+ std::vector<flatbuffers::Offset<executorch_flatbuffer::Chain>>{});
725+ auto empty_operators = builder.CreateVector (
726+ std::vector<flatbuffers::Offset<executorch_flatbuffer::Operator>>{});
727+ auto empty_delegates = builder.CreateVector (
728+ std::vector<
729+ flatbuffers::Offset<executorch_flatbuffer::BackendDelegate>>{});
730+ auto buffer_sizes = builder.CreateVector (std::vector<int64_t >{0 });
731+
732+ auto execution_plan = executorch_flatbuffer::CreateExecutionPlan (
733+ builder,
734+ plan_name,
735+ container_meta, // container_meta_type exists
736+ empty_values,
737+ empty_inputs,
738+ empty_outputs,
739+ empty_chains,
740+ empty_operators,
741+ empty_delegates,
742+ buffer_sizes);
743+
744+ auto execution_plans = builder.CreateVector (
745+ std::vector<flatbuffers::Offset<executorch_flatbuffer::ExecutionPlan>>{
746+ execution_plan});
747+
748+ auto empty_constant_buffer = builder.CreateVector (
749+ std::vector<flatbuffers::Offset<executorch_flatbuffer::Buffer>>{});
750+ auto empty_backend_data = builder.CreateVector (
751+ std::vector<flatbuffers::Offset<
752+ executorch_flatbuffer::BackendDelegateInlineData>>{});
753+ auto empty_segments = builder.CreateVector (
754+ std::vector<flatbuffers::Offset<executorch_flatbuffer::DataSegment>>{});
755+
756+ auto program = executorch_flatbuffer::CreateProgram (
757+ builder,
758+ 0 ,
759+ execution_plans,
760+ empty_constant_buffer,
761+ empty_backend_data,
762+ empty_segments);
763+
764+ builder.Finish (program, executorch_flatbuffer::ProgramIdentifier ());
765+
766+ // Copy to 16-byte aligned buffer (required by Program::load)
767+ alignas (16 ) uint8_t aligned_buffer[2048 ];
768+ ASSERT_LE (builder.GetSize (), sizeof (aligned_buffer));
769+ std::memcpy (aligned_buffer, builder.GetBufferPointer (), builder.GetSize ());
770+
771+ BufferDataLoader data_loader (aligned_buffer, builder.GetSize ());
772+ Result<Program> loaded_program =
773+ Program::load (&data_loader, Program::Verification::Minimal);
774+
775+ ASSERT_EQ (loaded_program.error (), Error::Ok);
776+
777+ // Should return error for missing encoded_out_str, not crash
778+ Result<const char *> encoding =
779+ loaded_program->get_output_flattening_encoding (" forward" );
780+
781+ EXPECT_EQ (encoding.error (), Error::InvalidProgram);
782+ }
0 commit comments