Hi. As requested in PR81715, GCC emits bigger middle redzones for small variables. It's analyzed in following comment: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715#c28
For now I'm suggesting to shrink shadow memory for variables <= 16B to 32B (including variable storage). LLVM is more aggressive as they allocate just 16B of shadow memory for variables <= 4B. That would require bigger code refactoring in asan.c and I would like to avoid that. For detailed statistics of Linux Kernel, please take a look here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715#c29 I'm testing the patch now. Thoughts? gcc/ChangeLog: 2018-09-25 Martin Liska <mli...@suse.cz> * cfgexpand.c (expand_stack_vars): Smaller middle redzones if requested. * doc/invoke.texi: New param. * params.def (PARAM_ASAN_STACK_SMALL_REDZONE): Likewise. * params.h (ASAN_STACK_SMALL_REDZONE): Likewise. gcc/testsuite/ChangeLog: 2018-09-25 Martin Liska <mli...@suse.cz> * c-c++-common/asan/asan-stack-small.c: New test. --- gcc/cfgexpand.c | 13 +++++++-- gcc/doc/invoke.texi | 3 ++ gcc/params.def | 6 ++++ gcc/params.h | 2 ++ .../c-c++-common/asan/asan-stack-small.c | 29 +++++++++++++++++++ 5 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/asan/asan-stack-small.c
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 35ca276e4ad..c735e9ca2a3 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -1128,9 +1128,18 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data) MAX (alignb, ASAN_RED_ZONE_SIZE), !FRAME_GROWS_DOWNWARD); tree repr_decl = NULL_TREE; + poly_uint64 size = stack_vars[i].size; + /* For small variables shrink middle redzone (including + * variable store) just to ASAN_RED_ZONE_SIZE. */ + if (ASAN_STACK_SMALL_REDZONE + && i != n - 1 + && (stack_vars[i].size.to_constant () + <= (ASAN_RED_ZONE_SIZE / 2))) + ; + else + size += ASAN_RED_ZONE_SIZE; offset - = alloc_stack_frame_space (stack_vars[i].size - + ASAN_RED_ZONE_SIZE, + = alloc_stack_frame_space (size, MAX (alignb, ASAN_RED_ZONE_SIZE)); data->asan_vec.safe_push (prev_offset); diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 7ef4e7a449b..1c55887b9cd 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -11313,6 +11313,9 @@ Enable buffer overflow detection for stack objects. This kind of protection is enabled by default when using @option{-fsanitize=address}. To disable stack protection use @option{--param asan-stack=0} option. +@item asan-stack-small-redzone +Emit smaller middle redzone for variables smaller or equal to 16 bytes. + @item asan-instrument-reads Enable buffer overflow detection for memory reads. This kind of protection is enabled by default when using @option{-fsanitize=address}. diff --git a/gcc/params.def b/gcc/params.def index 9f0697327d4..f1fafb4002d 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -1201,6 +1201,12 @@ DEFPARAM (PARAM_ASAN_STACK, "Enable asan stack protection.", 1, 0, 1) +DEFPARAM (PARAM_ASAN_STACK_SMALL_REDZONE, + "asan-stack-small-redzone", + "Emit smaller middle redzone for variables smaller " + "or equal to 16 bytes.", + 0, 0, 1) + DEFPARAM (PARAM_ASAN_PROTECT_ALLOCAS, "asan-instrument-allocas", "Enable asan allocas/VLAs protection.", diff --git a/gcc/params.h b/gcc/params.h index 8aa960a904e..42df40e66fd 100644 --- a/gcc/params.h +++ b/gcc/params.h @@ -236,6 +236,8 @@ extern void init_param_values (int *params); PARAM_VALUE (PARAM_ALLOW_PACKED_STORE_DATA_RACES) #define ASAN_STACK \ PARAM_VALUE (PARAM_ASAN_STACK) +#define ASAN_STACK_SMALL_REDZONE \ + PARAM_VALUE (PARAM_ASAN_STACK_SMALL_REDZONE) #define ASAN_PROTECT_ALLOCAS \ PARAM_VALUE (PARAM_ASAN_PROTECT_ALLOCAS) #define ASAN_GLOBALS \ diff --git a/gcc/testsuite/c-c++-common/asan/asan-stack-small.c b/gcc/testsuite/c-c++-common/asan/asan-stack-small.c new file mode 100644 index 00000000000..dc08edaad71 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/asan-stack-small.c @@ -0,0 +1,29 @@ +/* { dg-do run } */ +/* { dg-options "--param asan-stack-small-redzone=1" } */ + +char *pa; +char *pb; +char *pc; + +void access (volatile char *ptr) +{ + *ptr = 'x'; +} + +int main (int argc, char **argv) +{ + char a; + char b; + char c; + + pa = &a; + pb = &b; + pc = &c; + + access (pb); + access (pc); + // access 'b' here + access (pa + 32); + + return 0; +}