Skip to content

Decode constant call arguments before storing them in callee locals #1070

@Stevengre

Description

@Stevengre

#setArgsFromStack currently handles constant call arguments by forwarding the raw operandConstant(...) term into #setLocalValue:

rule <k> #setArgFromStack(IDX, operandConstant(_) #as CONSTOPERAND)
      =>
         #setLocalValue(place(local(IDX), .ProjectionElems), CONSTOPERAND)
      ...
     </k>

This is unsafe if the #setLocalValue write rule can fire before the constant operand is evaluated/decoded to a Value. In that case, the callee local may be written as typedValue(operandConstant(...), TY, MUT).

That violates the local-storage invariant documented in rt/value.md and rt/data.md: locals are TypedLocals, and a TypedValue must carry a Value payload. Later rules that rely on getValue(...), isValue(...), or projection traversal may then get stuck or continue with an invalid local payload.

The fix should keep the scope limited to call-argument setup:

  • add a regression test for passing a constant argument into a callee and reading it there;
  • ensure the constant argument is evaluated/decoded to a Value before it is stored in callee <locals>;
  • prevent raw Operand terms such as operandConstant(...) from appearing inside typedValue(...);
  • preserve the existing operandCopy / operandMove handling for caller locals, reference-height adjustment, and moved locals.

It is fine for an unevaluated construct to enter locals only through an explicit thunk(...), since that is itself a Value; the issue is storing a raw Operand as the TypedValue payload.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions