Skip to content

Fix null-deref when inlining an If branch that outputs an initializer#314

Merged
take-cheeze merged 4 commits into
onnx:mainfrom
take-cheeze:fix-if-const-cond-null-deref
Jul 23, 2026
Merged

Fix null-deref when inlining an If branch that outputs an initializer#314
take-cheeze merged 4 commits into
onnx:mainfrom
take-cheeze:fix-if-const-cond-null-deref

Conversation

@take-cheeze

Copy link
Copy Markdown
Member

Related to onnxsim/onnxsim#452

eliminate_if_with_const_cond inlines the taken branch of an If whose condition is a compile-time constant by re-creating the branch's nodes in the parent graph and mapping each subgraph output to its newly created parent value via value_dict.

value_dict is populated only from the outputs of the branch's nodes. When a branch output is produced by a constant initializer (kParam) or is a value captured from an outer scope (kCaptured) rather than by a node, its unique name is absent from value_dict. The output loop then did value_dict[name], which default-inserts a null Value*, and replaceAllUsesWith(nullptr) dereferenced it and crashed (segfault).

This is easy to trigger together with constant folding: onnx-simplifier's extract_constant_to_initializer turns a branch's Constant node into a subgraph initializer, after which that branch's output is a kParam value with no producing node.

Handle the kParam and kCaptured cases in the output loop the same way the node-input loop already does: copy a kParam initializer into the parent graph, and resolve a kCaptured value from the parent graph (creating a captured node when it comes from a further-out scope).

@take-cheeze
take-cheeze requested review from a team as code owners July 22, 2026 01:06
@andife
andife requested a review from Copilot July 22, 2026 03:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a crash in the eliminate_if_with_const_cond optimization pass when inlining a constant-condition If whose taken-branch output is not produced by a node (e.g., forwarded initializer / forwarded captured value). This improves robustness when the optimizer is run after constant-folding/extraction steps that turn Constant nodes into initializers.

Changes:

  • Resolves subgraph outputs via value_dict when possible, and adds explicit handling for kCaptured and kParam outputs when the output has no producing node.
  • Copies subgraph initializers into the parent graph for kParam outputs to avoid inserting nulls into the value map and segfaulting on replaceAllUsesWith.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +122 to +124
auto *captured_node = parent_graph.create(kCaptured, 1);
captured_node->output()->setUniqueName(unique_name);
new_output = captured_node->output();
Comment on lines +128 to +132
} else if (output_in_subgraph->node()->kind() == kParam) {
// The taken branch forwards a constant initializer straight to its
// output. This happens, for example, when constant folding (as done by
// onnx-simplifier) has already turned the branch's Constant node into a
// subgraph initializer, so there is no node producing this output and
take-cheeze and others added 3 commits July 22, 2026 13:23
Signed-off-by: take-cheeze <takechi101010@gmail.com>
eliminate_if_with_const_cond inlines the taken branch of an If whose
condition is a compile-time constant by re-creating the branch's nodes in
the parent graph and mapping each subgraph output to its newly created
parent value via value_dict.

value_dict is populated only from the outputs of the branch's *nodes*.
When a branch output is produced by a constant initializer (kParam) or is
a value captured from an outer scope (kCaptured) rather than by a node,
its unique name is absent from value_dict. The output loop then did
`value_dict[name]`, which default-inserts a null Value*, and
`replaceAllUsesWith(nullptr)` dereferenced it and crashed (segfault).

This is easy to trigger together with constant folding: onnx-simplifier's
extract_constant_to_initializer turns a branch's `Constant` node into a
subgraph initializer, after which that branch's output is a kParam value
with no producing node.

Handle the kParam and kCaptured cases in the output loop the same way the
node-input loop already does: copy a kParam initializer into the parent
graph, and resolve a kCaptured value from the parent graph (creating a
captured node when it comes from a further-out scope).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: take-cheeze <takechi101010@gmail.com>
- Insert the newly created kCaptured node into the parent graph so that
  downstream nodes made to depend on it via replaceAllUsesWith reference
  an attached node instead of a floating one, keeping the graph valid.
- Add a regression test covering the output-only case where the taken
  If-branch forwards a subgraph initializer straight to its output. It
  runs extract_constant_to_initializer before eliminate_if_with_const_cond
  to reproduce the onnxsim/onnxsim#452 segfault, which the pass now handles
  without dereferencing a null Value.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZiQnQnUQS3UCA9xzsocn1
Signed-off-by: take-cheeze <takechi101010@gmail.com>
@take-cheeze
take-cheeze force-pushed the fix-if-const-cond-null-deref branch from 3c79809 to ccefa42 Compare July 22, 2026 04:24
@take-cheeze
take-cheeze merged commit 96ddf59 into onnx:main Jul 23, 2026
29 checks passed
@take-cheeze
take-cheeze deleted the fix-if-const-cond-null-deref branch July 23, 2026 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants