Skip to content

runtime/executor: null-check backend_delegate_data#19904

Open
vacu9708 wants to merge 1 commit into
pytorch:mainfrom
vacu9708:null-check_backend_delegate_data
Open

runtime/executor: null-check backend_delegate_data#19904
vacu9708 wants to merge 1 commit into
pytorch:mainfrom
vacu9708:null-check_backend_delegate_data

Conversation

@vacu9708
Copy link
Copy Markdown
Contributor

@vacu9708 vacu9708 commented May 31, 2026

This PR continues the loader-hardening work in #16704, #18724, and #19267.

Bug

backend_delegate_data is an optional FlatBuffer vector (schema/program.fbs:506, no (required) attribute).

flowchart LR
    A["Method::load\nmethod.cpp:839"] -->|"for each BackendDelegate"| B["GetProcessedData\nmethod.cpp:193"]
    B -->|"location == INLINE"| C["get_backend_delegate_data\nprogram.cpp:534"]
    C -->|"backend_delegate_data() == null"| D["SIGSEGV"]
Loading

Fix

Add a null guard before the existing size check:

Condition Before After
backend_delegate_data() is null SIGSEGV InvalidProgram
entry->data() is null SIGSEGV InvalidProgram

InvalidProgram is used (rather than NotFound) because an absent backend_delegate_data while a delegate references inline data indicates a corrupt file, not a normal lookup miss. Happy to change if you prefer NotFound for symmetry with the index check.

The GetProcessedData function has two structurally parallel unguarded derefs (delegate.processed(), delegate.id()->c_str()); left for a follow-up to keep this PR focused.

Tests

$ cmake --build cmake-out --target program_test -j$(nproc)
[100%] Built target program_test

$ cd cmake-out && ctest -R '^program_test$'
100% tests passed, 0 tests failed out of 1

$ lintrunner runtime/executor/program.cpp runtime/executor/test/program_test.cpp
ok No lint issues.

cc @larryliu0820 @JacobSzwejbka @lucylq

@vacu9708 vacu9708 requested a review from JacobSzwejbka as a code owner May 31, 2026 11:24
@pytorch-bot
Copy link
Copy Markdown

pytorch-bot Bot commented May 31, 2026

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/19904

Note: Links to docs will display an error until the docs builds have been completed.

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 31, 2026
@github-actions
Copy link
Copy Markdown

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

@vacu9708 vacu9708 changed the title runtime/executor: null-check backend_delegate_data` runtime/executor: null-check backend_delegate_data May 31, 2026
@mergennachin
Copy link
Copy Markdown
Contributor

@claude Review this PR

@claude
Copy link
Copy Markdown

claude Bot commented Jun 1, 2026

Claude finished @mergennachin's task in 1m 15s —— View job


Review of PR #19904

  • Read changed files and gather context
  • Review implementation correctness
  • Review test coverage
  • Post review feedback

Verdict: This PR looks good. The fix is correct, minimal, and well-tested.

Correctness

The two null checks are properly placed and address real crash scenarios:

  1. data_list != nullptr (line 542) — Guards against a null backend_delegate_data() vector. Since the FlatBuffer schema (program.fbs:506) does not mark this field as (required), FlatBuffers will return nullptr for a missing/corrupt field. Without this check, the subsequent data_list->size() dereference would SIGSEGV.

  2. entry != nullptr ? entry->data() : nullptr (line 550) — Guards against a null entry within the vector. FlatBuffers vectors of tables can contain null entries (offset == 0 in the buffer). The ternary + subsequent ET_CHECK_OR_RETURN_ERROR cleanly avoids the deref.

Using InvalidProgram is the right error code here — a delegate referencing inline data that doesn't exist indicates a corrupt/malformed program file, not a normal miss.

Style

The code follows the existing patterns in program.cpp (e.g., the get_constant_buffer_data function just above uses the same ET_CHECK_OR_RETURN_ERROR idiom). No unnecessary comments; the error messages are descriptive enough.

Test

The test constructs a minimal FlatBuffer Program with backend_delegate_data=null (offset 0) and verifies that calling get_backend_delegate_data returns Error::InvalidProgram instead of crashing. This directly exercises the first null guard. The ProgramTestFriend accessor addition follows the established pattern.

Minor observation (non-blocking)

The test only covers the data_list == nullptr path. The second guard (entry->data() == nullptr) isn't explicitly tested — it would require constructing a BackendDelegateInlineData entry with a null data field. This is fine for a follow-up if desired, since the code path is straightforward.


Overall: clean, focused fix that converts a SIGSEGV into a proper error return. LGTM.

@nil-is-all nil-is-all added the module: runtime Issues related to the core runtime and code under runtime/ label Jun 1, 2026
@kirklandsign
Copy link
Copy Markdown
Contributor

Please fix linter


    126  126 |       size_t* out_size) {
    127  127 |     return program->get_backend_delegate_data(index, out_data, out_size);
    128  128 | 
    128      |-// Constructs a Program directly with a chosen segment_base_offset and a
    129      |-// pre-built FlatBuffer body. Used to set up malformed states (e.g.
    130      |-// segment_base_offset != 0 but segments == null) that Program::load cannot
    131      |-// produce, since segment_base_offset is driven only by the extended header.
    132      |-static Program MakeProgram(
    133      |-      DataLoader* loader,
    134      |-size_t segment_base_offset,
    135      |-const executorch_flatbuffer::Program* internal_program) {
    136      |-return Program(
    137      |-loader,
    138      |-segment_base_offset,
    139      |-FreeableBuffer{},
    140      |-internal_program,
    141      |-FreeableBuffer{},
    142      |-std::nullopt);
    143      |-}
    144      |-};
         129 |+// Constructs a Program directly with a chosen segment_base_offset and a
         130 |+// pre-built FlatBuffer body. Used to set up malformed states (e.g.
         131 |+// segment_base_offset != 0 but segments == null) that Program::load cannot
         132 |+// produce, since segment_base_offset is driven only by the extended header.
         133 |+static Program MakeProgram(
         134 |+        DataLoader * loader,
         135 |+size_t segment_base_offset,
         136 |+const executorch_flatbuffer::Program* internal_program) {
         137 |+return Program(
         138 |+loader,
         139 |+segment_base_offset,
         140 |+FreeableBuffer{},
         141 |+internal_program,
         142 |+FreeableBuffer{},
         143 |+std::nullopt);
         144 |+}
         145 |+};
    146  146 | } // namespace testing
    147  147 | } // namespace runtime
    148  148 | } // namespace executorch

`backend_delegate_data` is an optional FlatBuffer vector — legitimately
absent when no inline delegate blobs exist. The accessor dereferenced it
without a null check, causing a SIGSEGV on any such PTE. Neither the
FlatBuffer verifier nor validate_program catches this, so the crash was
reachable under both Minimal and InternalConsistency verification.

- Add `data_list != nullptr` guard; return `InvalidProgram` if absent.
- Add `data != nullptr` guard on the per-entry data field.

Continues the loader-hardening work in pytorch#16704, pytorch#18724, and pytorch#19267.

Signed-off-by: Youngsik Yang <vacu9708@gmail.com>
@vacu9708 vacu9708 force-pushed the null-check_backend_delegate_data branch from b84e98c to a52caf4 Compare June 5, 2026 00:36
@vacu9708
Copy link
Copy Markdown
Contributor Author

vacu9708 commented Jun 5, 2026

I've fixed the lint / build problem.
I am sorry for missing double-check before PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. module: runtime Issues related to the core runtime and code under runtime/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants