Skip to content

Give an escaped parameter a slot before reloading it - #339

Open
alanhc wants to merge 1 commit into
sysprog21:masterfrom
alanhc:fix-escaped-param-reload
Open

Give an escaped parameter a slot before reloading it#339
alanhc wants to merge 1 commit into
sysprog21:masterfrom
alanhc:fix-escaped-param-reload

Conversation

@alanhc

@alanhc alanhc commented Sep 10, 2026

Copy link
Copy Markdown

Fixes #337.

prepare_operand() reloads an address-taken variable from its stack slot
rather than reading the register it is already in, since a store through the
pointer would not have reached the register. The reload needs the slot to hold
the value, and for a parameter it does not: parameters arrive in registers,
and a slot is reserved the first time something spills one. Reloading before
that read whatever the frame happened to hold.

int f(int a, int b)
{
    int x = a - b;
    int *p = &b;
    return x;
}

returned a rather than a - b on all four targets, because the subtraction
read an uninitialised slot that happened to contain zero. Nothing is stored
through the pointer here; taking the address is enough, and the value is
already wrong before the pointer is ever used.

Write the register back before the reload when the variable has no slot yet,
which is what makes the slot stand for the variable, and go on using the
register it is already in.

The shape is narrow, which is likely why it has gone unnoticed: it needs the
escaped variable to be a parameter -- a local is stored to its slot when it is
initialised -- and the address to be taken after the expression rather than
before. tests/escaped-param.c covers the subtraction, the same shape around
an addition, and the address taken of the first operand rather than the
second.

The suite passes on x64, arm, arm64 and riscv at both stages;
clang-format-18 is clean on the changed files.

One thing I would like a second opinion on, repeated from the issue: this sits
in prepare_operand(), which everything goes through. A narrower fix in
whatever gives parameters their slots might be more appropriate -- I could not
find a natural place to do it there, because the slot is deliberately
allocated lazily.


Summary by cubic

Fixes #337: escaped parameters now write their register back to the stack slot before a reload, so address-taken parameters no longer read uninitialized frame memory.

  • Reloading a parameter without a slot previously read garbage from the frame, corrupting expressions like a - b where the address is taken after the computation.
  • prepare_operand() now stores the register to the slot first when no slot is allocated, then reloads from it.
  • Adds tests/escaped-param.c covering subtraction, addition, and the address taken of the first operand.

Written for commit 4bcb7fc. Summary will update on new commits.

Review in cubic

prepare_operand() reloads an address-taken variable from its stack slot
instead of reading the register holding it, since a store through the
pointer would not have reached the register. The reload assumes the slot
holds the variable, and for a parameter it does not: parameters arrive
in registers, and a slot is reserved the first time something spills
one. Reloading before that read whatever the frame happened to hold.

    int f(int a, int b)
    {
        int x = a - b;
        int *p = &b;
        return x;
    }

returned a rather than a - b, because the subtraction read an
uninitialised slot that happened to contain zero. Nothing is stored
through the pointer here; taking the address is enough, and the value
is wrong before the pointer is ever used.

Write the register back before the reload when the variable has no slot
yet, which is what makes the slot stand for the variable, and keep using
the register it is already in.

All three targets were affected.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 3 files

Re-trigger cubic

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.

Taking the address of a parameter corrupts an expression computed before it

1 participant