On Tue, 14 Jul 2026, Jakub Jelinek wrote: > Hi! > > If we have > .ASAN_MARK (UNPOISON, &a, 24); > .ASAN_MARK (UNPOISON, &b, 24); > p_7 = &a; > q_8 = &b; > .ASAN_MARK (POISON, &a, 24); > .ASAN_MARK (POISON, &b, 24); > _1 = *p_7; > _2 = *q_8; > _3 = _1 + _2; > <retval> = _3; > return <retval>; > or > .ASAN_MARK (UNPOISON, &a, 24); > .ASAN_MARK (UNPOISON, &b, 24); > p_4 = &a; > q_5 = &b; > .ASAN_MARK (POISON, &a, 24); > .ASAN_MARK (POISON, &b, 24); > *p_4 = 1; > *q_5 = 2; > return; > which represent load or store uses after scope and decide not to make the > vars addressable anymore, we turn that into > a_10 = .ASAN_POISON (); > b_11 = .ASAN_POISON (); > _1 = a_10 + b_11; > <retval> = _1; > return <retval>; > or > a_8 = .ASAN_POISON (); > b_9 = .ASAN_POISON (); > .ASAN_POISON_USE (a_8); > .ASAN_POISON_USE (b_9); > return; > These 2 internal fns are something that is normally lowere during > sanopt. Now, if the involved vars are large/huge _BitInt, the bitintlower > pass doesn't handle them and we end up with invalid IL (we try to change > the lhs of .ASAN_POISON from SSA_NAME to a var etc. which violates what > sanopt expects and get an extra .ASAN_POISON_USE while doing that etc. > > I thought what would be the best way to deal with these, e.g. try to replace > them with something tracking just one limb in those (although it is nicer to > report the proper sizes in asan rather than just small part of it), but > the .ASAN_POISON () uses can be also PHI args and some PHI args could be > .ASAN_POISON () uses while others could be unrelated SSA_NAMEs, so we'd > need to change those uses to be extensions from the .ASAN_POISONed limb > into full size on all edges and what to do with abnormal edges etc. > > So, in the end I've decided instead to just perform what sanopt pass does > for these 2 ifns if large/huge _BitInt is involved at the start of the > bitintlower pass (similarly how we lower switches there). > > The asan.cc changes are needed so that we can properly report 24 bytes > or 568 bytes etc. READs or WRITEs after scope. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK. Thanks, Richard. > 2026-07-14 Jakub Jelinek <[email protected]> > > PR middle-end/126084 > * gimple-lower-bitint.cc: Include "attribs.h" and "asan.h". > (gimple_lower_bitint): Use asan_expand_poison_ifn to lower > .ASAN_POISON calls with large/huge _BitInt lhs. > * asan.cc (report_error_func): Set *nargs and use _n builtin > even if size is not a power of two or larger than 16. > (asan_expand_poison_ifn): Handle nargs == 2. > > * gcc.dg/asan/bitint-1.c: New test. > * gcc.dg/asan/bitint-2.c: New test. > > --- gcc/gimple-lower-bitint.cc.jj 2026-07-08 11:09:58.434724804 +0200 > +++ gcc/gimple-lower-bitint.cc 2026-07-13 15:43:50.414954519 +0200 > @@ -56,6 +56,8 @@ along with GCC; see the file COPYING3. > #include "ubsan.h" > #include "stor-layout.h" > #include "gimple-lower-bitint.h" > +#include "attribs.h" > +#include "asan.h" > > /* Split BITINT_TYPE precisions in 4 categories. Small _BitInt, where > target hook says it is a single limb, middle _BitInt which per ABI > @@ -7319,6 +7321,40 @@ gimple_lower_bitint (void) > free_dominance_info (CDI_DOMINATORS); > free_dominance_info (CDI_POST_DOMINATORS); > mark_virtual_operands_for_renaming (cfun); > + cleanup_tree_cfg (TODO_update_ssa); > + } > + } > + > + if (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_HWADDRESS)) > + { > + hash_map<tree, tree> shadow_vars_mapping; > + bool need_commit_edge_insert = false; > + bool any_asan_poison = false; > + for (unsigned j = 0; j < num_ssa_names; ++j) > + { > + tree s = ssa_name (j); > + if (s == NULL) > + continue; > + tree type = TREE_TYPE (s); > + if (BITINT_TYPE_P (type) > + && gimple_call_internal_p (SSA_NAME_DEF_STMT (s), > + IFN_ASAN_POISON) > + && bitint_precision_kind (type) >= bitint_prec_large) > + { > + any_asan_poison = true; > + gimple_stmt_iterator gsi = gsi_for_stmt (SSA_NAME_DEF_STMT (s)); > + asan_expand_poison_ifn (&gsi, &need_commit_edge_insert, > + shadow_vars_mapping); > + } > + } > + if (any_asan_poison) > + { > + if (need_commit_edge_insert) > + gsi_commit_edge_inserts (); > + i = 0; > + free_dominance_info (CDI_DOMINATORS); > + free_dominance_info (CDI_POST_DOMINATORS); > + mark_virtual_operands_for_renaming (cfun); > cleanup_tree_cfg (TODO_update_ssa); > } > } > --- gcc/asan.cc.jj 2026-05-30 17:45:09.339110356 +0200 > +++ gcc/asan.cc 2026-07-13 16:17:42.135726685 +0200 > @@ -2536,8 +2536,13 @@ report_error_func (bool is_store, bool r > *nargs = 2; > return builtin_decl_implicit (report[recover_p][is_store][5]); > } > - *nargs = 1; > int size_log2 = exact_log2 (size_in_bytes); > + if (size_log2 == -1 || size_log2 >= 5) > + { > + *nargs = 2; > + return builtin_decl_implicit (report[recover_p][is_store][5]); > + } > + *nargs = 1; > return builtin_decl_implicit (report[recover_p][is_store][size_log2]); > } > > @@ -4380,8 +4385,12 @@ asan_expand_poison_ifn (gimple_stmt_iter > { > tree fun = report_error_func (store_p, recover_p, tree_to_uhwi (size), > &nargs); > - call = gimple_build_call (fun, 1, > - build_fold_addr_expr (shadow_var)); > + call = gimple_build_call (fun, nargs, > + build_fold_addr_expr (shadow_var), > + nargs == 2 > + ? fold_convert (pointer_sized_int_node, > + size) > + : NULL_TREE); > } > gimple_set_location (call, gimple_location (use)); > gimple *call_to_insert = call; > --- gcc/testsuite/gcc.dg/asan/bitint-1.c.jj 2026-07-13 16:25:06.148278451 > +0200 > +++ gcc/testsuite/gcc.dg/asan/bitint-1.c 2026-07-13 16:29:19.034189583 > +0200 > @@ -0,0 +1,26 @@ > +/* PR middle-end/126084 */ > +/* { dg-do run { target bitint575 } } */ > +/* { dg-shouldfail "asan" } */ > +/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */ > + > +_BitInt(135) > +foo () > +{ > + _BitInt(135) *p, *q; > + { > + _BitInt(135) a, b; > + p = &a; > + q = &b; > + } > + return *p + *q; > +} > + > +int > +main () > +{ > + volatile _BitInt(135) x = foo (); > +} > + > +/* { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on > address.*(\n|\r\n|\r)" } */ > +/* { dg-output "READ of size .*" } */ > +/* { dg-output ".*'a' \\(line 11\\) <== Memory access at offset \[0-9\]* is > inside this variable.*" } */ > --- gcc/testsuite/gcc.dg/asan/bitint-2.c.jj 2026-07-13 16:25:09.077242677 > +0200 > +++ gcc/testsuite/gcc.dg/asan/bitint-2.c 2026-07-13 16:29:50.433806054 > +0200 > @@ -0,0 +1,27 @@ > +/* PR middle-end/126084 */ > +/* { dg-do run { target bitint575 } } */ > +/* { dg-shouldfail "asan" } */ > +/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */ > + > +void > +foo () > +{ > + _BitInt(135) *p, *q; > + { > + _BitInt(135) a, b; > + p = &a; > + q = &b; > + } > + *p = 1; > + *q = 2; > +} > + > +int > +main () > +{ > + foo (); > +} > + > +/* { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on > address.*(\n|\r\n|\r)" } */ > +/* { dg-output "WRITE of size .*" } */ > +/* { dg-output ".*'a' \\(line 11\\) <== Memory access at offset \[0-9\]* is > inside this variable.*" } */ > > Jakub > > -- Richard Biener <[email protected]> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Jochen Jaser, Andrew McDonald; (HRB 36809, AG Nuernberg)
