Fix computed goto into statement expression (undefined behavior)#7
Merged
guillerodriguez merged 1 commit intomasterfrom Feb 5, 2026
Merged
Fix computed goto into statement expression (undefined behavior)#7guillerodriguez merged 1 commit intomasterfrom
guillerodriguez merged 1 commit intomasterfrom
Conversation
The DEF_OPC_JMP macros in interp-inlining.h place BRANCH labels
inside GCC statement expressions ({ }). These labels are targets
of computed gotos via the interpreter dispatch table. Per GCC
documentation, jumping into a statement expression with a computed
goto is undefined behavior [1], so this is fragile and not
guaranteed to work.
Although GCC does detect this in some simple cases, it does not
catch it in JamVM, possibly due to the way the code is structured
(label addresses are collected into the dispatch table separately
from the goto *pc->handler dispatch in the interpreter loop).
Clang 17+ performs whole-function analysis of indirect goto targets
and rejects the code with a hard error:
error: cannot jump from this indirect goto statement to one of
its possible targets
note: possible target of indirect goto statement
note: jump enters a statement expression
Only interp-inlining.h is affected. The other interpreter variants
(interp-direct.h, interp-indirect.h) do not create labels inside
statement expressions in their BRANCH macros.
Fix by changing ({ }) to { } in DEF_OPC_JMP. The statement
expression return value was never used (BODY is in statement context
and always exits via goto *pc->handler), so the change is purely
syntactic. Double checked that GCC produces byte-identical machine
code with and without this change for all optimization levels.
[1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
Signed-off-by: Guillermo Rodríguez <grodriguez@ingelabs.com>
Contributor
Author
|
From GCC documentation:
|
avazquezdev
approved these changes
Feb 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The DEF_OPC_JMP macros in interp-inlining.h place BRANCH labels inside GCC statement expressions ({ }). These labels are targets of computed gotos via the interpreter dispatch table. Per GCC documentation, jumping into a statement expression with a computed goto is undefined behavior 1, so this is fragile and not guaranteed to work.
Although GCC does detect this in some simple cases, it does not catch it in JamVM, possibly due to the way the code is structured (label addresses are collected into the dispatch table separately from the goto *pc->handler dispatch in the interpreter loop). Clang 17+ performs whole-function analysis of indirect goto targets and rejects the code with a hard error:
error: cannot jump from this indirect goto statement to one of
its possible targets
note: possible target of indirect goto statement
note: jump enters a statement expression
Only interp-inlining.h is affected. The other interpreter variants (interp-direct.h, interp-indirect.h) do not create labels inside statement expressions in their BRANCH macros.
Fix by changing ({ }) to { } in DEF_OPC_JMP. The statement expression return value was never used (BODY is in statement context and always exits via goto *pc->handler), so the change is purely syntactic. Double checked that GCC produces byte-identical machine code with and without this change for all optimization levels.