https://gcc.gnu.org/g:fe4b4a282d8875b04b4f6641441ed75eefb8ab62

commit r16-9227-gfe4b4a282d8875b04b4f6641441ed75eefb8ab62
Author: Martin Uecker <[email protected]>
Date:   Mon Jun 1 20:57:09 2026 +0200

    c: fix wrong code with counted_by attribute [PR123569]
    
    For an access to a member of pointer type with counted_by attribute,
    the .ACCESS_WITH_SIZE internal function is inserted at certain places
    before reading the pointer.  This leads to wrong code for increment
    and decrement operations.  For now, do not instrument these accesses
    by using default_array_function_conversion instead of
    default_array_function_read_conversion and calling mark_exp_read_
    directly.  Code to undo the effect of mark_exp_read can be removed,
    and the logic is moved into a helper function mark_exp_read_cond.
    
            PR c/123569
    
    gcc/c/ChangeLog:
            * c-parser.cc (mark_exp_read_cond): New function.
            (c_parser_unary_expression): Use mark_exp_read_cond.
            (c_parser_postfix_expression_after_primary): Likewise.
            * c-typeck.cc (build_unary_op): Remove dead code and
            add checking assertion.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/pr123569.c: New test.
    
    (cherry picked from commit 7149edfb90f3279f89b76942d3d0c9b94912bcad)

Diff:
---
 gcc/c/c-parser.cc               | 70 +++++++++++++++++------------------------
 gcc/c/c-typeck.cc               | 10 +++---
 gcc/testsuite/gcc.dg/pr123569.c | 22 +++++++++++++
 3 files changed, 54 insertions(+), 48 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index a7a8a41e7e2e..4cf2d8851662 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10646,6 +10646,26 @@ c_parser_cast_expression (c_parser *parser, struct 
c_expr *after)
     return c_parser_unary_expression (parser);
 }
 
+
+/* Like mark_exp_read but skip marking VAR_DECLs and PARM_DECLs
+   depending on the warning mode.  This helper function is
+   used in c_parser_unary_expression and
+   and c_parser_postfix_expression_after_primary for
+   pre/post-increment/decrement operations.
+ */
+
+static void
+mark_exp_read_cond (tree exp)
+{
+  if ((VAR_P (exp) || TREE_CODE (exp) == PARM_DECL)
+      && (VAR_P (exp) ? warn_unused_but_set_variable
+                     : warn_unused_but_set_parameter) > 1)
+    return;
+
+  mark_exp_read (exp);
+}
+
+
 /* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3).
 
    unary-expression:
@@ -10703,31 +10723,15 @@ c_parser_unary_expression (c_parser *parser)
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      if ((VAR_P (op.value) || TREE_CODE (op.value) == PARM_DECL)
-         && !DECL_READ_P (op.value)
-         && (VAR_P (op.value) ? warn_unused_but_set_variable
-                              : warn_unused_but_set_parameter) > 1)
-       {
-         op = default_function_array_read_conversion (exp_loc, op);
-         DECL_READ_P (op.value) = 0;
-       }
-      else
-       op = default_function_array_read_conversion (exp_loc, op);
+      mark_exp_read_cond (op.value);
+      op = default_function_array_conversion (exp_loc, op);
       return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op);
     case CPP_MINUS_MINUS:
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      if ((VAR_P (op.value) || TREE_CODE (op.value) == PARM_DECL)
-         && !DECL_READ_P (op.value)
-         && (VAR_P (op.value) ? warn_unused_but_set_variable
-                              : warn_unused_but_set_parameter) > 1)
-       {
-         op = default_function_array_read_conversion (exp_loc, op);
-         DECL_READ_P (op.value) = 0;
-       }
-      else
-       op = default_function_array_read_conversion (exp_loc, op);
+      mark_exp_read_cond (op.value);
+      op = default_function_array_conversion (exp_loc, op);
       return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op);
     case CPP_AND:
       c_parser_consume_token (parser);
@@ -14197,17 +14201,8 @@ c_parser_postfix_expression_after_primary (c_parser 
*parser,
          start = expr.get_start ();
          finish = c_parser_peek_token (parser)->get_finish ();
          c_parser_consume_token (parser);
-         if ((VAR_P (expr.value) || TREE_CODE (expr.value) == PARM_DECL)
-             && !DECL_READ_P (expr.value)
-             && (VAR_P (expr.value) ? warn_unused_but_set_variable
-                                    : warn_unused_but_set_parameter) > 1
-             && TREE_CODE (TREE_TYPE (expr.value)) != ARRAY_TYPE)
-           {
-             expr = default_function_array_read_conversion (expr_loc, expr);
-             DECL_READ_P (expr.value) = 0;
-           }
-         else
-           expr = default_function_array_read_conversion (expr_loc, expr);
+         mark_exp_read_cond (expr.value);
+         expr = default_function_array_conversion (expr_loc, expr);
          expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR,
                                       expr.value, false);
          set_c_expr_source_range (&expr, start, finish);
@@ -14219,17 +14214,8 @@ c_parser_postfix_expression_after_primary (c_parser 
*parser,
          start = expr.get_start ();
          finish = c_parser_peek_token (parser)->get_finish ();
          c_parser_consume_token (parser);
-         if ((VAR_P (expr.value) || TREE_CODE (expr.value) == PARM_DECL)
-             && !DECL_READ_P (expr.value)
-             && (VAR_P (expr.value) ? warn_unused_but_set_variable
-                                    : warn_unused_but_set_parameter) > 1
-             && TREE_CODE (TREE_TYPE (expr.value)) != ARRAY_TYPE)
-           {
-             expr = default_function_array_read_conversion (expr_loc, expr);
-             DECL_READ_P (expr.value) = 0;
-           }
-         else
-           expr = default_function_array_read_conversion (expr_loc, expr);
+         mark_exp_read_cond (expr.value);
+         expr = default_function_array_conversion (expr_loc, expr);
          expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR,
                                       expr.value, false);
          set_c_expr_source_range (&expr, start, finish);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 3ffeed73d8ce..a038d0990910 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -5781,9 +5781,10 @@ build_unary_op (location_t location, enum tree_code 
code, tree xarg,
   tree ret = error_mark_node;
   tree eptype = NULL_TREE;
   const char *invalid_op_diag;
-  bool int_operands;
 
-  int_operands = EXPR_INT_CONST_OPERANDS (xarg);
+  gcc_checking_assert (!is_access_with_size_p (arg));
+
+  bool int_operands = EXPR_INT_CONST_OPERANDS (xarg);
   if (int_operands)
     arg = remove_c_maybe_const_expr (arg);
 
@@ -6245,10 +6246,7 @@ build_unary_op (location_t location, enum tree_code 
code, tree xarg,
          goto return_build_unary_op;
        }
 
-      /* Ordinary case; arg is a COMPONENT_REF or a decl, or a call to
-        .ACCESS_WITH_SIZE.  */
-      if (is_access_with_size_p (arg))
-       arg = TREE_OPERAND (TREE_OPERAND (CALL_EXPR_ARG (arg, 0), 0), 0);
+      /* Ordinary case; arg is a COMPONENT_REF or a decl.  */
 
       argtype = TREE_TYPE (arg);
 
diff --git a/gcc/testsuite/gcc.dg/pr123569.c b/gcc/testsuite/gcc.dg/pr123569.c
new file mode 100644
index 000000000000..508f9f1e7e20
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr123569.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-std=c99" } */
+
+struct buffer {
+    int len;
+    char * ptr __attribute((counted_by(len)));
+};
+int ltrim(struct buffer * const buf) {
+    while (buf->len > 0 && *buf->ptr == ' ') {
+        buf->len--;
+        buf->ptr++;
+    }
+    return buf->len;
+}
+int main() {
+    struct buffer buf = {.ptr = " 123", .len = 4};
+    int ret = ltrim(&buf);
+    if (3 != ret)
+      __builtin_abort();
+    return 0;
+}
+

Reply via email to