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)

Reply via email to