https://gcc.gnu.org/g:7149edfb90f3279f89b76942d3d0c9b94912bcad

commit r17-1269-g7149edfb90f3279f89b76942d3d0c9b94912bcad
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.

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 6e8688d33eaf..b578de7b15aa 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10656,6 +10656,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:
@@ -10713,31 +10733,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);
@@ -14207,17 +14211,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);
@@ -14229,17 +14224,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 3606fc66abf4..fade28a392b5 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -5786,9 +5786,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);
 
@@ -6250,10 +6251,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