Hi! I've rushed up the PR117178 multi-dimensional nonstring support. Before a week off I've just bootstrapped/regtested the actual change, so handle_nonstring_attribute/get_attr_nonstring_decl adjustments after playing with simple short tests and left the testcases for the next day, where I've basically copied the attr-nonstring-{1,...,8}.c tests to attr-nonstring-{9,...,16}.c and adjusted them so that they test multi-dimensional nonstring instead of single-dimensional ones. But I forgot I haven't finished adjusting the dg-* lines and a few others to make all the tests pass and posted the patch for review anyway. When it got approved recently, I've only found out that some of the tests still FAIL when about to commit it and quickly adjusted them, but I've added 4 xfails in there. Sorry.
The following patch fixes those 4 xfails (and results in 2 false positive warnings not being produced either). The thing is that maybe_warn_nonstring_arg simply assumed that nonstring arrays must be single-dimensional, so when it sees a nonstring decl with ARRAY_TYPE, it just used its dimension. With multi-dimensional arrays that is not the right dimension to use though, it can be dimension of some outer dimension, e.g. if we have char a[5][6][7] __attribute__((nonstring)) if decl is a[5] it would assume maximum non-NUL terminated string length of 5 rather than 7, if a[5][6] it would assume 6 and only for a[5][6][0] it would assume the correct 7. So, the following patch looks through all the outer dimensions to reach the innermost one (which for attribute nonstring is guaranteed to have char/unsigned char/signed char element type). Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2025-03-10 Jakub Jelinek <ja...@redhat.com> PR c/117178 * gimple-ssa-warn-access.cc (maybe_warn_nonstring_arg): Look through multi-dimensional array types, stop at the innermost ARRAY_TYPE. * c-c++-common/attr-nonstring-11.c: Remove xfails. * c-c++-common/attr-nonstring-12.c (warn_strcmp_cst_1, warn_strcmp_cst_2): Don't expect any warnings here. (warn_strcmp_cst_3, warn_strcmp_cst_4): New functions with expected warnings. --- gcc/gimple-ssa-warn-access.cc.jj 2025-01-02 11:23:17.000000000 +0100 +++ gcc/gimple-ssa-warn-access.cc 2025-03-08 11:44:09.304064889 +0100 @@ -602,6 +602,10 @@ maybe_warn_nonstring_arg (tree fndecl, G bool known_size = false; tree type = TREE_TYPE (decl); + while (TREE_CODE (type) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE) + type = TREE_TYPE (type); + /* Determine the array size. For arrays of unknown bound and pointers reset BOUND to trigger the appropriate warning. */ if (TREE_CODE (type) == ARRAY_TYPE) --- gcc/testsuite/c-c++-common/attr-nonstring-11.c.jj 2025-03-08 00:49:09.958121143 +0100 +++ gcc/testsuite/c-c++-common/attr-nonstring-11.c 2025-03-08 11:50:15.513041709 +0100 @@ -165,8 +165,8 @@ void test_strcmp (struct MemArrays *p) void test_strncmp_warn (struct MemArrays *p) { enum { N = sizeof arr[2] }; - T (strncmp (str[2], arr[2], N)); /* { dg-bogus "argument 2 declared attribute 'nonstring' is smaller than the specified bound 4" "" { xfail *-*-* } } */ - T (strncmp (arr[2], str[2], N)); /* { dg-bogus "argument 1 declared attribute 'nonstring' is smaller than the specified bound 4" "" { xfail *-*-* } } */ + T (strncmp (str[2], arr[2], N)); + T (strncmp (arr[2], str[2], N)); T (strncmp (str[2], arr[2], N + 1)); /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 5" } */ T (strncmp (arr[2], str[2], N + 1)); /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 5" } */ @@ -237,7 +237,7 @@ void test_stpncpy_warn (struct MemArrays enum { N = sizeof arr[2] }; T (stpncpy (str[2], str[2], N)); - T (stpncpy (str[2], arr[2], N)); /* { dg-bogus "argument 2 declared attribute 'nonstring' is smaller than the specified bound 4" "" { xfail *-*-* } } */ + T (stpncpy (str[2], arr[2], N)); T (stpncpy (arr[2], str[2], N)); T (stpncpy (str[2], *ptr, N)); @@ -370,7 +370,7 @@ void test_stnrdup_warn (struct MemArrays enum { N = sizeof arr[2] }; T (strndup (str[2], N)); - T (strndup (arr[2], N)); /* { dg-bogus "argument 1 declared attribute 'nonstring' is smaller than the specified bound 4" "" { xfail *-*-* } } */ + T (strndup (arr[2], N)); T (strndup (*ptr, N)); T (strndup (*parr, N)); --- gcc/testsuite/c-c++-common/attr-nonstring-12.c.jj 2025-03-08 00:07:01.879907901 +0100 +++ gcc/testsuite/c-c++-common/attr-nonstring-12.c 2025-03-08 11:52:11.850445944 +0100 @@ -26,12 +26,22 @@ enum { X = sizeof ar5[2] + 1 }; int warn_strcmp_cst_1 (void) { - return strcmp ("bar", arx[3]); /* { dg-warning "argument 2 declared attribute .nonstring." } */ + return strcmp ("bar", arx[3]); } int warn_strcmp_cst_2 (void) { - return strcmp (arx[3], "foo"); /* { dg-warning "argument 1 declared attribute .nonstring." } */ + return strcmp (arx[3], "foo"); +} + +int warn_strcmp_cst_3 (void) +{ + return strcmp ("barfoobazquxcorge1", arx[3]); /* { dg-warning "argument 2 declared attribute .nonstring." } */ +} + +int warn_strcmp_cst_4 (void) +{ + return strcmp (arx[3], "foobarbazquxcorge1"); /* { dg-warning "argument 1 declared attribute .nonstring." } */ } Jakub