Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.
like image 654
Frank Avatar asked Sep 05 '18 16:09

Frank


1 Answers

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
...
like image 56
Peter Cordes Avatar answered Oct 02 '22 20:10

Peter Cordes