Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to return a stack-allocated structure by value?

Tags:

c

c99

[Note: This is reposted from https://softwareengineering.stackexchange.com/q/369604/126197, where for some reason this question got immediately downvoted. Twice. Clearly there's more love over here!]

Here's a bit of code paraphrased from a vendor's example.

I've looked for authoritative documentation on passing stack-allocated structures by value, but haven't found the definitive word. In a nutshell: Does C99 guarantee this to be safe?

typedef struct {
    int32_t upper;
    int32_t lower;
} boundaries_t;

static boundaries_t calibrate() {
    boundaries_t boundaries;         // struct allocated on stack

    boundaries.upper = getUpper();
    boundaries.lower = getLower();
    return boundaries;               // return struct by value
}

int main() {
    boundaries_t b;

    b = calibrate();
    // do stuff with b
    ...
}

Note that calibrate() allocates the boundaries struct on the stack and then returns it by value.

If the compiler can guarantee that the stack frame for calibrate() will be intact at the time of the assignment to b, then all is well. Perhaps that's part of the contract in C99's pass-by-value?

(Context: my world is embedded systems where pass-by-value is rarely seen. I do know that returning a pointer from a stack-allocated structure is a recipe for disaster, but this pass-by-value stuff feels alien.)

like image 828
fearless_fool Avatar asked Apr 26 '26 07:04

fearless_fool


1 Answers

Yes, it's perfectly safe. When you return by value it copies the members of the structure into the caller's structure. As long as the structure doesn't contain any pointers to local objects, it's valid.

Returning structures tends to be uncommon, because if they're large it requires lots of copying. But sometimes we put arrays into structures to allow them to be passed and returned by value (arrays normally decay to pointers when used as parameters or return values) like other data types.

addendum by original asker

(I trust @Barmar won't mind...)

As @DanielH pointed out, in the case of SysV ABI for amd64, the compiler will make provisions for returning the struct by value. If it's small, the entire struct can be returned in a register (read: fast). If it's larger, the compiler allocates room in the caller's stack frame and passes a pointer to the callee. The callee then copies the value of the struct into that upon return. From the doc:

If the type has class MEMORY, then the caller provides space for the return value and passes the address of this storage in %rdi as if it were the first argument to the function. In effect, this address becomes a “hidden” first argument.

like image 146
Barmar Avatar answered Apr 28 '26 21:04

Barmar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!