https://gcc.gnu.org/g:0d60b63b8310f8c6cd32518f4e3fb1123cafd24f

commit r14-12747-g0d60b63b8310f8c6cd32518f4e3fb1123cafd24f
Author: Jakub Jelinek <[email protected]>
Date:   Tue Jul 14 10:39:55 2026 +0200

    bitintlower: Handle .ASAN_POISON and .ASAN_POISON_USE with large/huge 
_BitInt [PR126084]
    
    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.
    
    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.
    
    Reviewed-by: Richard Biener <[email protected]>
    (cherry picked from commit 8837b1d542fb685da3b36176a0bd82a46f472b80)

Diff:
---
 gcc/asan.cc                          | 15 ++++++++++++---
 gcc/gimple-lower-bitint.cc           | 36 ++++++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/asan/bitint-1.c | 26 ++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/asan/bitint-2.c | 27 +++++++++++++++++++++++++++
 4 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/gcc/asan.cc b/gcc/asan.cc
index 268bb9fe0707..b19be889982c 100644
--- a/gcc/asan.cc
+++ b/gcc/asan.cc
@@ -2379,8 +2379,13 @@ report_error_func (bool is_store, bool recover_p, 
HOST_WIDE_INT size_in_bytes,
       *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]);
 }
 
@@ -4219,8 +4224,12 @@ asan_expand_poison_ifn (gimple_stmt_iterator *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;
diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc
index 7399587d16bf..05f7e9291067 100644
--- a/gcc/gimple-lower-bitint.cc
+++ b/gcc/gimple-lower-bitint.cc
@@ -56,6 +56,8 @@ along with GCC; see the file COPYING3.  If not see
 #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
@@ -6175,6 +6177,40 @@ gimple_lower_bitint (void)
        }
     }
 
+  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);
+       }
+    }
+
   struct bitint_large_huge large_huge;
   bool has_large_huge_parm_result = false;
   bool has_large_huge = false;
diff --git a/gcc/testsuite/gcc.dg/asan/bitint-1.c 
b/gcc/testsuite/gcc.dg/asan/bitint-1.c
new file mode 100644
index 000000000000..8f32f1f421dd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/bitint-1.c
@@ -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.*" } */
diff --git a/gcc/testsuite/gcc.dg/asan/bitint-2.c 
b/gcc/testsuite/gcc.dg/asan/bitint-2.c
new file mode 100644
index 000000000000..47048449e303
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/bitint-2.c
@@ -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.*" } */

Reply via email to