Hi. As always Jakub provided my very nice hint how to fix the issue. It's about adding representative of a stack partitioning into asan_handled_variables when another variable of the partition lies in asan_handled_variables.
Patch survives testing on ppc64le-linux-gnu. Ready for trunk? gcc/ChangeLog: 2018-09-21 Martin Liska <mli...@suse.cz> PR sanitizer/85774 * asan.c: Make asan_handled_variables extern. * asan.h: Likewise. * cfgexpand.c (expand_stack_vars): Make sure a representative is unpoison if another variable in the partition is handled by use-after-scope sanitization. gcc/testsuite/ChangeLog: 2018-09-21 Martin Liska <mli...@suse.cz> PR sanitizer/85774 * g++.dg/asan/pr85774.C: New test. --- gcc/asan.c | 2 +- gcc/asan.h | 2 ++ gcc/cfgexpand.c | 14 ++++++++ gcc/testsuite/g++.dg/asan/pr85774.C | 51 +++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/asan/pr85774.C
diff --git a/gcc/asan.c b/gcc/asan.c index e71ab2cc710..235e219479d 100644 --- a/gcc/asan.c +++ b/gcc/asan.c @@ -253,7 +253,7 @@ static tree last_alloca_addr; /* Set of variable declarations that are going to be guarded by use-after-scope sanitizer. */ -static hash_set<tree> *asan_handled_variables = NULL; +hash_set<tree> *asan_handled_variables = NULL; hash_set <tree> *asan_used_labels = NULL; diff --git a/gcc/asan.h b/gcc/asan.h index 412af220597..2f431b4f938 100644 --- a/gcc/asan.h +++ b/gcc/asan.h @@ -110,6 +110,8 @@ extern bool asan_sanitize_stack_p (void); extern bool asan_sanitize_allocas_p (void); +extern hash_set<tree> *asan_handled_variables; + /* Return TRUE if builtin with given FCODE will be intercepted by libasan. */ diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index c8d7805308c..35ca276e4ad 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -1155,6 +1155,20 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data) if (repr_decl == NULL_TREE) repr_decl = stack_vars[i].decl; data->asan_decl_vec.safe_push (repr_decl); + + /* Make sure a representative is unpoison if another + variable in the partition is handled by + use-after-scope sanitization. */ + if (asan_handled_variables != NULL + && !asan_handled_variables->contains (repr_decl)) + { + for (j = i; j != EOC; j = stack_vars[j].next) + if (asan_handled_variables->contains (stack_vars[j].decl)) + break; + if (j != EOC) + asan_handled_variables->add (repr_decl); + } + data->asan_alignb = MAX (data->asan_alignb, alignb); if (data->asan_base == NULL) data->asan_base = gen_reg_rtx (Pmode); diff --git a/gcc/testsuite/g++.dg/asan/pr85774.C b/gcc/testsuite/g++.dg/asan/pr85774.C new file mode 100644 index 00000000000..c033abfd69b --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/pr85774.C @@ -0,0 +1,51 @@ +/* PR sanitizer/85774 */ +/* { dg-do run } */ + +#include <functional> + +void +DoSomething () +{ +} + +void +DoFunc (const std::function<void(void)> &func) +{ + func (); +} + +void +Setup () +{ + switch (1) + { + case 1: + { + DoFunc ([]() {}); + break; + } + case 2: + { + DoFunc ([]() {}); + break; + } + default: + break; + } + + DoSomething (); +} + +void +DemostrateBadPoisoning () +{ + DoFunc ([]() {}); +} + +int +main () +{ + Setup (); + DemostrateBadPoisoning (); + return 0; +}