What's the expected behavior of stack protection with statically-sized arrays?

  • A+
Category:Languages

If I compile the following in Ubuntu 16.04 / gcc 7.3

struct VecA {   float data[4]; };  struct VecB {   float x;   float y;   float z;   float w; };  // Requires stack protection VecA getA() {return {1.0f, 1.0f, 1.0f, 1.0f};}  // Does not require stack protection VecB getB() {return {1.0f, 1.0f, 1.0f, 1.0f};} 

Like so:

g++ -O3 -c -o result test.cpp objdump -d result 

I get:

0000000000000000 <_Z4getAv>:    0:   48 83 ec 18             sub    $0x18,%rsp    4:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax    b:   00 00     d:   48 89 44 24 08          mov    %rax,0x8(%rsp)   12:   31 c0                   xor    %eax,%eax   14:   f3 0f 7e 05 00 00 00    movq   0x0(%rip),%xmm0        # 1c <_Z4getAv+0x1c>   1b:   00    1c:   48 8b 44 24 08          mov    0x8(%rsp),%rax   21:   64 48 33 04 25 28 00    xor    %fs:0x28,%rax   28:   00 00    2a:   75 09                   jne    35 <_Z4getAv+0x35>   2c:   66 0f 6f c8             movdqa %xmm0,%xmm1   30:   48 83 c4 18             add    $0x18,%rsp   34:   c3                      retq      35:   e8 00 00 00 00          callq  3a <_Z4getAv+0x3a>   3a:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)  0000000000000040 <_Z4getBv>:   40:   f3 0f 7e 05 00 00 00    movq   0x0(%rip),%xmm0        # 48 <_Z4getBv+0x8>   47:   00    48:   66 0f 6f c8             movdqa %xmm0,%xmm1   4c:   c3                      retq  

Which "looks" like linux stack protection is being applied to VecA. A little bit on the defensive side, but I can understand how a compiler could reach that conclusion.

However, This is where i'm getting confused:

I can't reproduce this on godbolt.org, even with stack protection explicitly on. I can make it happen for BOTH functions with -fstack-protector-all but that's expected, and uninteresting.

https://gcc.godbolt.org/z/ePR98P

Also, it seems that, on my system, explicitly using the stack protector is removing the protection from getA()

g++ -O3 -c -o -fstack-protector result test.cpp objdump -d result  0000000000000000 <_Z4getAv>:    0:   f3 0f 7e 05 00 00 00    movq   0x0(%rip),%xmm0        # 8 <_Z4getAv+0x8>    7:   00     8:   66 0f 6f c8             movdqa %xmm0,%xmm1    c:   c3                      retq       d:   0f 1f 00                nopl   (%rax)  0000000000000010 <_Z4getBv>:   10:   f3 0f 7e 05 00 00 00    movq   0x0(%rip),%xmm0        # 18 <_Z4getBv+0x8>   17:   00    18:   66 0f 6f c8             movdqa %xmm0,%xmm1   1c:   c3                      retq    

So my questions are:

  1. Why are my local results that much different than what's being generated on godbolt.org?

  2. Is there a reasonable explanation behind the behavior on my system? Especially regarding -fstack-protector removing protection.

  3. It is reasonable to assert that both functions should be generating equivalent assembly in optimized code?

Edit:

Full version string:

g++ --version g++ (Ubuntu 7.3.0-21ubuntu1~16.04) 7.3.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

 


The default on Ubuntu's gcc is -fstack-protector-strong, not -fstack-protector-all. (The gcc manual lists available options).

https://lwn.net/Articles/584225/ describes "strong". It really likes to protect arrays, but structs with no array members can't be indexed so there's much less chance of overflow.

On Godbolt, that produces stack protection for VecA but not VecB, like on your desktop. (And BTW, you can use g++ -S -masm=intel -O3 to get Intel-syntax, or objdump -drwC -Mintel, since you linked to Intel-syntax on Godbolt.)

You can use g++ -S -fverbose-asm -O3 foo.cpp to include comments showing all the implied and explicit options gcc used when compiling. On Godbolt, uncheck the // icon to not hide asm comments, like this.

# GNU C++14 (GCC-Explorer-Build) version 7.3.0 (x86_64-linux-gnu) #       compiled by GNU C version 5.4.0 20160609, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.16.1-GMP  # GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 # options passed:  -fdiagnostics-color=always -imultiarch x86_64-linux-gnu # -iprefix /opt/compiler-explorer/gcc-7.3.0/bin/../lib/gcc/x86_64-linux-gnu/7.3.0/ # -D_GNU_SOURCE # /tmp/compiler-explorer-compiler11885-54-1u26why.tdoy/example.cpp # -masm=intel -mtune=generic -march=x86-64 # -auxbase-strip /tmp/compiler-explorer-compiler11885-54-1u26why.tdoy/output.s # -g -O3 -std=gnu++14 -fstack-protector-strong -fverbose-asm # options enabled:  -faggressive-loop-optimizations -falign-labels # -fasynchronous-unwind-tables -fauto-inc-dec -fbranch-count-reg # -fcaller-saves -fchkp-check-incomplete-type -fchkp-check-read # -fchkp-check-write -fchkp-instrument-calls -fchkp-narrow-bounds # -fchkp-optimize -fchkp-store-bounds -fchkp-use-static-bounds # -fchkp-use-static-const-bounds -fchkp-use-wrappers -fcode-hoisting # -fcombine-stack-adjustments -fcommon -fcompare-elim -fcprop-registers # -fcrossjumping -fcse-follow-jumps -fdefer-pop ... 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: