GCC considers PTRDIFF_MAX - 1 to be the size of the largest object so that the difference between a pointer to the byte just past its end and the first one is no more than PTRDIFF_MAX. This is too liberal in LP64 on most systems because the size of the address space is constrained to much less than that, both by the width of the address bus for physical memory and by the practical limitations of disk sizes for swap files.
I've been meaning to add a parameter to specify a lower size limit to help detect more bugs due to excessive sizes in various function calls (malloc, memcpy, etc.), and also to help better verify that warnings use the limit correctly. Attached is a patch that adds this parameter. Testing it exposed a few minor bugs in GCC, both in the AWK script that processes parameter and option files, as well as in the warning code (and in tests that exercise it). Martin
Add new parameter max-object-size. gcc/ChangeLog: * builtins.c (warn_string_no_nul): Print parameter when it's set. (maybe_warn_for_bound): Same. (compute_objsize_r): Use new parameter. * calls.c (alloc_max_size): Same. * gimple-ssa-sprintf.c (get_string_length): Same. * gimple-ssa-warn-restrict.c (maybe_diag_access_bounds): * opt-functions.awk (function var_type_struct): Test for Host_Wide_Int. * params.opt (max-object-size): New parameter. * tree-ssa-strlen.c (maybe_set_strlen_range): Use new parameter. (get_len_or_size): Same. * tree.c (max_object_size): Same. gcc/testsuite/ChangeLog: * c-c++-common/Warray-bounds-2.c: Adjust to new parameter value. * c-c++-common/Warray-bounds-3.c: Same. * c-c++-common/Wrestrict.c: Same. * g++.dg/warn/Wplacement-new-size-5.C: Same. * gcc.dg/Wstringop-overflow-41.c: Same. * gcc.dg/Wstringop-overflow-50.c: Same. * gcc.dg/Wstringop-overflow-54.c: Same. * gcc.dg/Wstringop-overflow-62.c: Same. * gcc.dg/Wstringop-overread-2.c: Same. * gcc.dg/attr-nonstring-2.c: Same. * gcc.dg/attr-nonstring-3.c: Same. * gcc.dg/attr-nonstring-4.c: Same. * gcc.dg/strlenopt-40.c: Same. * gcc.dg/Wstringop-overflow-64.c: New test. diff --git a/gcc/builtins.c b/gcc/builtins.c index aad99da01c2..78ffad5ccab 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -1127,6 +1122,7 @@ warn_string_no_nul (location_t loc, tree expr, const char *fname, (unsigned long long) bndrng[1].to_uhwi ()); } + bool max_exceed = false; const tree maxobjsize = max_object_size (); const wide_int maxsiz = wi::to_wide (maxobjsize); if (expr) @@ -1134,7 +1130,8 @@ warn_string_no_nul (location_t loc, tree expr, const char *fname, tree func = get_callee_fndecl (expr); if (bndrng) { - if (wi::ltu_p (maxsiz, bndrng[0])) + max_exceed = wi::ltu_p (maxsiz, bndrng[0]); + if (max_exceed) warned = warning_at (loc, OPT_Wstringop_overread, "%K%qD specified bound %s exceeds " "maximum object size %E", @@ -1165,7 +1162,8 @@ warn_string_no_nul (location_t loc, tree expr, const char *fname, { if (bndrng) { - if (wi::ltu_p (maxsiz, bndrng[0])) + max_exceed = wi::ltu_p (maxsiz, bndrng[0]); + if (max_exceed) warned = warning_at (loc, OPT_Wstringop_overread, "%qs specified bound %s exceeds " "maximum object size %E", @@ -1195,8 +1193,16 @@ warn_string_no_nul (location_t loc, tree expr, const char *fname, if (warned) { - inform (DECL_SOURCE_LOCATION (decl), - "referenced argument declared here"); + if (max_exceed) + { + if (param_max_object_size < HOST_WIDE_INT_MAX) + inform (loc, + "set by %<%s %llu%>", + "--param max-object-size", param_max_object_size); + } + else + inform (DECL_SOURCE_LOCATION (decl), + "referenced argument declared here"); TREE_NO_WARNING (arg) = 1; if (expr) TREE_NO_WARNING (expr) = 1; @@ -3955,7 +3961,9 @@ maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func, { bool maybe = pad && pad->src.phi (); - if (tree_int_cst_lt (maxobjsize, bndrng[0])) + /* Set when the maximum object size has been exceeded. */ + const bool max_exceed = tree_int_cst_lt (maxobjsize, bndrng[0]); + if (max_exceed) { if (bndrng[0] == bndrng[1]) warned = (func @@ -4027,7 +4035,14 @@ maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func, exp, bndrng[0], bndrng[1], size)); if (warned) { - if (pad && pad->src.ref) + if (max_exceed) + { + if (param_max_object_size < HOST_WIDE_INT_MAX) + inform (loc, + "set by %<%s=%llu%>", + "--param max-object-size", param_max_object_size); + } + else if (pad && pad->src.ref) { if (DECL_P (pad->src.ref)) inform (DECL_SOURCE_LOCATION (pad->src.ref), @@ -4043,7 +4058,10 @@ maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func, } bool maybe = pad && pad->dst.phi (); - if (tree_int_cst_lt (maxobjsize, bndrng[0])) + + /* Set when the maximum object size has been exceeded. */ + const bool max_exceed = tree_int_cst_lt (maxobjsize, bndrng[0]); + if (max_exceed) { if (bndrng[0] == bndrng[1]) warned = (func @@ -4116,7 +4134,14 @@ maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func, if (warned) { - if (pad && pad->dst.ref) + if (max_exceed) + { + if (param_max_object_size < HOST_WIDE_INT_MAX) + inform (loc, + "set by %<%s %llu%>", + "--param max-object-size", param_max_object_size); + } + else if (pad && pad->dst.ref) { if (DECL_P (pad->dst.ref)) inform (DECL_SOURCE_LOCATION (pad->dst.ref), @@ -5434,7 +5459,7 @@ compute_objsize_r (tree ptr, access_ref *pref, pointer_query *qry, length or one-element). Set the size to the maximum minus the constant size of the type. */ pref->sizrng[0] = 0; - pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node)); + pref->sizrng[1] = param_max_object_size; if (tree recsize = TYPE_SIZE_UNIT (TREE_TYPE (ref))) if (TREE_CODE (recsize) == INTEGER_CST) pref->sizrng[1] -= wi::to_offset (recsize); diff --git a/gcc/calls.c b/gcc/calls.c index 4114bf5e5b2..eea67720ad6 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1236,7 +1236,7 @@ alloc_max_size (void) HOST_WIDE_INT limit = warn_alloc_size_limit; if (limit == HOST_WIDE_INT_MAX) - limit = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node)); + limit = param_max_object_size; alloc_object_size_limit = build_int_cst (size_type_node, limit); diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc index 87e9b3b046a..bc024507d25 100644 --- a/gcc/gimple-array-bounds.cc +++ b/gcc/gimple-array-bounds.cc @@ -998,8 +998,10 @@ array_bounds_checker::ptrs_to_distinct (tree ptr[2], tree ref[2]) if (!is_gimple_call (def_stmt)) return false; tree fntype = gimple_call_fntype (def_stmt); - if (lookup_attribute ("alloc_size", TYPE_ATTRIBUTES (fntype)) - || gimple_call_builtin_p (def_stmt, BUILT_IN_ALLOCA_WITH_ALIGN)) + if (fntype + && (lookup_attribute ("alloc_size", TYPE_ATTRIBUTES (fntype)) + || gimple_call_builtin_p (def_stmt, + BUILT_IN_ALLOCA_WITH_ALIGN))) refbits[i] |= ref_alloc; else refbits[i] |= ref_unknown; @@ -1218,9 +1220,9 @@ array_bounds_checker::handle_assign () default: lhs = gimple_assign_lhs (curstmt); ptr = gimple_assign_rhs1 (curstmt); - if (!POINTER_TYPE_P (TREE_TYPE (lhs))) - return false; - + if (!POINTER_TYPE_P (TREE_TYPE (lhs)) + || !POINTER_TYPE_P (TREE_TYPE (ptr))) + return false; offrng[0] = offrng[1] = 0; } diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index ca0572f53d3..f4820a02ef5 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -2057,7 +2057,7 @@ get_string_length (tree str, gimple *stmt, unsigned eltsize, return res; } - unsigned HOST_WIDE_INT lenmax = tree_to_uhwi (max_object_size ()) - 2; + unsigned HOST_WIDE_INT lenmax = param_max_object_size - 1; if (integer_zerop (lendata.minlen) && (!lendata.maxbound || lenmax <= tree_to_uhwi (lendata.maxbound)) && lenmax <= tree_to_uhwi (lendata.maxlen)) diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index 3a79e7240f9..84b92a37507 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -1698,19 +1698,28 @@ maybe_diag_access_bounds (gimple *call, tree func, int strict, if (warn_stringop_overflow) { + /* TODO: Call maybe_warn_for_bound() instead. */ + bool warned; if (ref.sizrange[0] == ref.sizrange[1]) - return warning_at (loc, OPT_Wstringop_overflow_, - "%G%qD specified bound %wu " - "exceeds maximum object size %wu", - call, func, ref.sizrange[0].to_uhwi (), - maxobjsize.to_uhwi ()); - - return warning_at (loc, OPT_Wstringop_overflow_, - "%G%qD specified bound between %wu and %wu " - "exceeds maximum object size %wu", - call, func, ref.sizrange[0].to_uhwi (), - ref.sizrange[1].to_uhwi (), - maxobjsize.to_uhwi ()); + warned = warning_at (loc, OPT_Wstringop_overflow_, + "%G%qD specified bound %wu " + "exceeds maximum object size %wi", + call, func, ref.sizrange[0].to_uhwi (), + maxobjsize.to_uhwi ()); + else + warned = warning_at (loc, OPT_Wstringop_overflow_, + "%G%qD specified bound between %wu and %wu " + "exceeds maximum object size %wi", + call, func, ref.sizrange[0].to_uhwi (), + ref.sizrange[1].to_uhwi (), + maxobjsize.to_uhwi ()); + + if (warned && param_max_object_size < HOST_WIDE_INT_MAX) + inform (loc, + "set by %<%s=%llu%>", + "--param max-object-size", param_max_object_size); + + return warned; } } diff --git a/gcc/opt-functions.awk b/gcc/opt-functions.awk index b4952b89315..bd2ec609509 100644 --- a/gcc/opt-functions.awk +++ b/gcc/opt-functions.awk @@ -254,6 +254,8 @@ function var_type_struct(flags) en = opt_args("Enum", flags); return enum_type[en] " " } + else if (flag_set_p("Host_Wide_Int", flags)) + return "HOST_WIDE_INT " else if (!flag_set_p("Joined.*", flags) && !flag_set_p("Separate", flags)) { if (flag_set_p(".*Mask.*", flags)) { if (host_wide_int[var_name(flags)] == "yes") diff --git a/gcc/params.opt b/gcc/params.opt index 5b00284c1fb..d458b7f01b1 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -561,6 +561,10 @@ The maximum number of insns in loop header duplicated by the copy loop headers p Common Joined UInteger Var(param_max_modulo_backtrack_attempts) Init(40) Param Optimization The maximum number of backtrack attempts the scheduler should make when modulo scheduling a loop. +-param=max-object-size= +Common Joined ByteSize Host_Wide_Int Var(param_max_object_size) Init(HOST_WIDE_INT_MAX) Param Optimization +The size of the largest object. + -param=max-partial-antic-length= Common Joined UInteger Var(param_max_partial_antic_length) Init(100) Param Optimization Maximum length of partial antic set when performing tree pre optimization. diff --git a/gcc/testsuite/c-c++-common/Warray-bounds-2.c b/gcc/testsuite/c-c++-common/Warray-bounds-2.c index 7400a29d4be..9aaada3cf3b 100644 --- a/gcc/testsuite/c-c++-common/Warray-bounds-2.c +++ b/gcc/testsuite/c-c++-common/Warray-bounds-2.c @@ -176,14 +176,14 @@ wrap_strncpy_src_diff_max_m1 (char *d, const char *s, ptrdiff_t i, size_t n) { /* Unlike in the similar call to memcpy(), there is no pointer overflow here because the size N is not added to the source - offset MAX - 1 (only 1 is for the access to its first element, + offset MAX - 2 (only 1 is for the access to its first element, which is tested below). */ strncpy (d, s + i, n); } void call_strncpy_src_diff_max_m1 (char *d, const char *s, size_t n) { - wrap_strncpy_src_diff_max_m1 (d, s, MAX - 1, 3); + wrap_strncpy_src_diff_max_m1 (d, s, MAX - 2, 3); } static void diff --git a/gcc/testsuite/c-c++-common/Warray-bounds-3.c b/gcc/testsuite/c-c++-common/Warray-bounds-3.c index d9b3864203f..682769a5465 100644 --- a/gcc/testsuite/c-c++-common/Warray-bounds-3.c +++ b/gcc/testsuite/c-c++-common/Warray-bounds-3.c @@ -25,6 +25,7 @@ extern char* strncpy (char* restrict, const char* restrict, size_t); #endif void sink (void*, ...); +#define sink(p, ...) sink (0, (__INTPTR_TYPE__)p) #define CAT(x, y) x ## y #define CONCAT(x, y) CAT (x, y) @@ -157,7 +158,7 @@ void test_memcpy_overflow (char *d, const char *s, size_t n) /* Verify that offset overflow involving an array of unknown size but known access size is detected. This works except with small sizes that are powers of 2 due to bug . */ - T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 1); + T (char, 1, arr + SR (DIFF_MAX - 2, DIFF_MAX), s, 1); T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 2); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 2 accessing array " "bug " { xfail non_strict_align } } */ T (char, 1, arr + SR (DIFF_MAX - 2, DIFF_MAX), s, 3); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 3 accessing array " "memcpy" } */ T (char, 1, arr + SR (DIFF_MAX - 4, DIFF_MAX), s, 5); /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 5 accessing array " "memcpy" } */ diff --git a/gcc/testsuite/c-c++-common/Wrestrict.c b/gcc/testsuite/c-c++-common/Wrestrict.c index 9eb02bdbfcb..e9f9aee1f00 100644 --- a/gcc/testsuite/c-c++-common/Wrestrict.c +++ b/gcc/testsuite/c-c++-common/Wrestrict.c @@ -314,11 +314,11 @@ void test_memcpy_anti_range (char *d, const char *s) T (d, d + SAR (0, 3), 1); T (d, d + SAR (0, 3), 2); T (d, d + SAR (0, 3), 3); - T (d, d + SAR (0, 3), DIFF_MAX - 2); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 2" "memcpy" } */ - T (d, d + SAR (0, 3), DIFF_MAX - 1); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 1" "memcpy" } */ - T (d, d + SAR (0, 3), DIFF_MAX); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 0" "memcpy" } */ + T (d, d + SAR (0, 3), DIFF_MAX - 3); /* { dg-warning "overlaps \\d+ bytes at offset 2 " "memcpy" } */ + T (d, d + SAR (0, 3), DIFF_MAX - 2); /* { dg-warning "overlaps \\d+ bytes at offset 1" "memcpy" } */ + T (d, d + SAR (0, 3), DIFF_MAX - 1); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 0" "memcpy" } */ - T (d, d + SAR (0, 3), UR (DIFF_MAX - 2, DIFF_MAX)); /* { dg-warning "accessing \[0-9\]+ or more bytes at offsets 0 and \\\[-?\[0-9\]+, -?\[0-9\]+] overlaps \[0-9\]+ bytes at offset 2" "memcpy" } */ + T (d, d + SAR (0, 3), UR (DIFF_MAX - 2, DIFF_MAX)); /* { dg-warning "accessing \[0-9\]+ or more bytes at offsets 0 and \\\[-?\[0-9\]+, -?\[0-9\]+] overlaps \[0-9\]+ bytes at offset 1" "memcpy" } */ /* Verify that a size in an anti-range ~[1, N] where N >= PTRDIFF_MAX - 2 doesn't trigger a warning. @@ -327,7 +327,7 @@ void test_memcpy_anti_range (char *d, const char *s) ptrdiff_t. Since such a large object cannot exist, so the size of the region must be zero. */ T (d, s, UAR (1, DIFF_MAX / 2 - 1)); - T (d, s, UAR (1, DIFF_MAX - 1)); + T (d, s, UAR (1, DIFF_MAX - 2)); T (d, s, UAR (1, DIFF_MAX)); T (d, s, UAR (1, SIZE_MAX - 1)); T (d, s, UAR (1, SIZE_MAX)); @@ -358,37 +358,37 @@ void test_memcpy_range_exceed (char *d, const char *s) whose aggregate size would exceed DIFF_MAX if it were to not overlap. */ T (d, s, DIFF_MAX / 2); - T (d, s, DIFF_MAX / 2 + 1); /* { dg-warning "overlaps 1 byte" "memcpy" } */ - T (d, s, DIFF_MAX / 2 + 2); /* { dg-warning "overlaps 3 bytes" "memcpy" } */ - T (d, s, DIFF_MAX / 2 + 3); /* { dg-warning "overlaps 5 bytes" "memcpy" } */ + T (d, s, DIFF_MAX / 2 + 1); /* { dg-warning "overlaps 2 bytes" "memcpy" } */ + T (d, s, DIFF_MAX / 2 + 2); /* { dg-warning "overlaps 4 bytes" "memcpy" } */ + T (d, s, DIFF_MAX / 2 + 3); /* { dg-warning "overlaps 6 bytes" "memcpy" } */ i = SR (DIFF_MAX - 2, DIFF_MAX); /* Verify a warning for an out-of-bounds offset range and constant size addition. */ - T (d, d + i, 3); /* { dg-warning "accessing 3 bytes at offsets 0 and \\\[\[0-9\]+, \[0-9\]+] overlaps 1 byte" "memcpy" } */ - T (d + i, d, 3); /* { dg-warning "accessing 3 bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and 0 overlaps 1 byte" "memcpy" } */ + T (d, d + i, 3); /* { dg-warning "accessing 3 bytes at offsets 0 and \\\[\[0-9\]+, \[0-9\]+] overlaps 2 bytes" "memcpy" } */ + T (d + i, d, 3); /* { dg-warning "accessing 3 bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and 0 overlaps 2 bytes" "memcpy" } */ - T (d + 1, d + i, 3); /* { dg-warning "accessing 3 bytes at offsets 1 and \\\[\[0-9\]+, \[0-9\]+] overlaps 1 byte" "memcpy" } */ - T (d + i, d + 1, 3); /* { dg-warning "accessing 3 bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and 1 overlaps 1 byte" "memcpy" } */ + T (d + 1, d + i, 3); /* { dg-warning "accessing 3 bytes at offsets 1 and \\\[\[0-9\]+, \[0-9\]+] overlaps 2 bytes" "memcpy" } */ + T (d + i, d + 1, 3); /* { dg-warning "accessing 3 bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and 1 overlaps 2 bytes" "memcpy" } */ /* Verify that the warnings above are independent of whether the source and destination are known to be based on the same object. */ - T (d, s + i, 3); /* { dg-warning "accessing 3 bytes at offsets 0 and \\\[\[0-9\]+, \[0-9\]+] overlaps 1 byte" "memcpy" } */ - T (d + i, s, 3); /* { dg-warning "accessing 3 bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and 0 overlaps 1 byte" "memcpy" } */ + T (d, s + i, 3); /* { dg-warning "accessing 3 bytes at offsets 0 and \\\[\[0-9\]+, \[0-9\]+] overlaps 2 bytes" "memcpy" } */ + T (d + i, s, 3); /* { dg-warning "accessing 3 bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and 0 overlaps 2 bytes" "memcpy" } */ - T (d + 1, s + i, 3); /* { dg-warning "accessing 3 bytes at offsets 1 and \\\[\[0-9\]+, \[0-9\]+] overlaps 1 byte" "memcpy" } */ - T (d + i, s + 1, 3); /* { dg-warning "accessing 3 bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and 1 overlaps 1 byte" "memcpy" } */ + T (d + 1, s + i, 3); /* { dg-warning "accessing 3 bytes at offsets 1 and \\\[\[0-9\]+, \[0-9\]+] overlaps 2 bytes" "memcpy" } */ + T (d + i, s + 1, 3); /* { dg-warning "accessing 3 bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and 1 overlaps 2 bytes" "memcpy" } */ #if __SIZEOF_SIZE_T__ == 8 /* Verfiy the offset and size computation is correct. The overlap offset mentioned in the warning plus sthe size of the access must not exceed DIFF_MAX. */ - T (d, d + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[9223372036854775805, 9223372036854775807] overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */ - T (d + i, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[9223372036854775805, 9223372036854775807] and 0 overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */ + T (d, d + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[9223372036854775805, 9223372036854775807] overlaps 4 bytes at offset 9223372036854775801" "LP64" { target lp64 } } */ + T (d + i, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[9223372036854775805, 9223372036854775807] and 0 overlaps 4 bytes at offset 9223372036854775801" "LP64" { target lp64 } } */ - T (d, s + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[9223372036854775805, 9223372036854775807] overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */ - T (d + i, s, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[9223372036854775805, 9223372036854775807] and 0 overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */ + T (d, s + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[9223372036854775805, 9223372036854775807] overlaps 4 bytes at offset 9223372036854775801" "LP64" { target lp64 } } */ + T (d + i, s, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[9223372036854775805, 9223372036854775807] and 0 overlaps 4 bytes at offset 9223372036854775801" "LP64" { target lp64 } } */ #elif __SIZEOF_SIZE_T__ == 4 T (d, d + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2147483645, 2147483647] overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */ T (d + i, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */ @@ -408,7 +408,7 @@ void test_memcpy_range_exceed (char *d, const char *s) n = UR (4, SIZE_MAX - 1); T (d + i, d + j, n); - j = SR (DIFF_MAX - 8, DIFF_MAX - 1); + j = SR (DIFF_MAX - 9, DIFF_MAX - 1); T (d + i, d + j, n); j = SR (DIFF_MAX - 7, DIFF_MAX - 1); @@ -417,20 +417,20 @@ void test_memcpy_range_exceed (char *d, const char *s) j = SR (DIFF_MAX - 6, DIFF_MAX - 1); T (d + i, d + j, n); /* { dg-warning "accessing 4( or more)? bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and \\\[\[0-9\]+, \[0-9\]+] overlaps" "memcpy" } */ - n = UR (3, DIFF_MAX); + n = UR (2, DIFF_MAX); T (d + i, d + j, n); - j = SR (DIFF_MAX - 6, DIFF_MAX - 1); + j = SR (DIFF_MAX - 7, DIFF_MAX - 1); T (d + i, d + j, n); - j = SR (DIFF_MAX - 5, DIFF_MAX - 1); - T (d + i, d + j, n); /* { dg-warning "accessing 3 or more bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and \\\[\[0-9\]+, \[0-9\]+] overlaps 1 or more bytes" "memcpy" } */ + j = SR (DIFF_MAX - 3, DIFF_MAX - 1); + T (d + i, d + j, n); /* { dg-warning "accessing 3 or more bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and \\\[\[0-9\]+, \[0-9\]+] overlaps 2 or more bytes" "memcpy" } */ j = SR (DIFF_MAX - 4, DIFF_MAX - 1); T (d + i, d + j, n); /* { dg-warning "accessing 3 or more bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and \\\[\[0-9\]+, \[0-9\]+] overlaps 1 or more bytes" "memcpy" } */ j = SR (DIFF_MAX - 2, DIFF_MAX - 1); - T (d + i, d + j, n); /* { dg-warning "accessing 3 or more bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and \\\[\[0-9\]+, \[0-9\]+] overlaps 1 or more bytes" "memcpy" } */ + T (d + i, d + j, n); /* { dg-warning "accessing 2 or more bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and \\\[\[0-9\]+, \[0-9\]+] overlaps 1 or more bytes" "memcpy" } */ } /* Exercise memcpy with destination and source of unknown size. */ diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-5.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-5.C index 4afc7e503ab..7786419e3ee 100644 --- a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-5.C +++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-5.C @@ -236,7 +236,8 @@ void test_vla (unsigned n) new (&cvla[9]) A; new (&cvla[n - 1]) A; new (cvla + n - 1) A; - new (&cvla[DIFF_MAX - 1]) A; + new (&cvla[DIFF_MAX - 2]) A; + new (&cvla[DIFF_MAX - 1]) A; // { dg-warning "\\\[-Wplacement-new"} new (&cvla[DIFF_MAX]) A; // { dg-warning "\\\[-Wplacement-new" } new (cvla + DIFF_MAX) A; // { dg-warning "\\\[-Wplacement-new" } new (&cvla[SIZE_MAX]) A; // { dg-warning "\\\[-Wplacement-new" } diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-41.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-41.c index 9b2d2cbc501..d0790c22abb 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-41.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-41.c @@ -16,10 +16,10 @@ void sink (void*); void char_array_cst_off_cst_size (void) { - extern char caxcc[]; // { dg-message "at offset \\d+ into destination object 'caxcc'" } + extern char caxcc[]; // { dg-message "at offset \\d+ into destination object 'caxcc'" "note" } char *p = caxcc; - size_t idx = DIFF_MAX - 3; + size_t idx = DIFF_MAX - 4; memset (p + idx, 0, 3); sink (p); @@ -43,29 +43,29 @@ void char_array_var_off_cst_size (size_t idx) bound of DIFF_MAX. There's not point in also mentioning the latter (it wouldn't make the note any more meaningful) so verify it only mentions the lower bound. */ - extern char caxvc[]; // { dg-message "at offset \\d+ into destination object 'caxvc'" "note" } + extern char caxvc[]; // { dg-message "at offset \\\[\\d+, \\d+] into destination object 'caxvc'" "note" } char *p = caxvc; - if (idx < DIFF_MAX - 3) - idx = DIFF_MAX - 3; + if (idx < DIFF_MAX - 4) + idx = DIFF_MAX - 4; memset (p + idx, 0, 3); sink (p); - memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" } + memset (p + idx, 0, 4); // { dg-warning "writing 4 bytes into a region of size 3" } sink (p); } void char_array_var_off_var_size (size_t idx, size_t n) { - extern char caxvv[]; // { dg-message "at offset \\d+ into destination object 'caxvv'" "note" } + extern char caxvv[]; // { dg-message "at offset \\\[\\d+, \\d+] into destination object 'caxvv'" "note" } char *p = caxvv; - if (idx < DIFF_MAX - 3) - idx = DIFF_MAX - 3; + if (idx < DIFF_MAX - 4) + idx = DIFF_MAX - 4; if (n < 3 || 7 < n) n = 3; @@ -81,10 +81,10 @@ void char_array_var_off_var_size (size_t idx, size_t n) void alloc_array_var_off_cst_size (size_t n, size_t idx) { - char *p = malloc (n); // { dg-message "at offset \\d+ into destination object" "note" } + char *p = malloc (n); // { dg-message "at offset \\\[\\d+, \\d+] into destination object" "note" } - if (idx < DIFF_MAX - 3) - idx = DIFF_MAX - 3; + if (idx < DIFF_MAX - 4) + idx = DIFF_MAX - 4; memset (p + idx, 0, 3); sink (p); @@ -101,10 +101,10 @@ void int_array_cst_off_cst_size (void) int *p = iaxc; size_t idx = DIFF_MAX / sizeof *iaxc; - memset (p + idx, 0, 3); + memset (p + idx, 0, 2); sink (p); - memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" } + memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 2" } sink (p); } diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-50.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-50.c index 7df58e5209e..a784b65bee5 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-50.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-50.c @@ -17,7 +17,7 @@ char* fcall (void); void char_ptr_cst_off_cst_size (char *p) // { dg-message "at offset \[1-9\]\[0-9\]+ into destination object 'p'" "note" { target *-*-* } .-1 } { - size_t idx = DIFF_MAX - 3; + size_t idx = DIFF_MAX - 4; memset (p + idx, 0, 3); sink (p); @@ -43,8 +43,8 @@ void char_ptr_var_difoff_cst_size (ptrdiff_t idx) mentions the lower bound. { dg-message "at offset \\d+ into destination object of size \\\[0, \\d+] (allocated|returned) by 'fcall'" "note" { target *-*-* } .-5 } */ - if (idx < DIFF_MAX - 3) - idx = DIFF_MAX - 3; + if (idx < DIFF_MAX - 4) + idx = DIFF_MAX - 4; memset (p + idx, 0, 3); sink (p); @@ -60,8 +60,8 @@ void char_ptr_var_szoff_cst_size (size_t idx) char *p = gptr; - if (idx < DIFF_MAX - 3) - idx = DIFF_MAX - 3; + if (idx < DIFF_MAX - 4) + idx = DIFF_MAX - 4; memset (p + idx, 0, 3); sink (p); @@ -78,8 +78,8 @@ void char_ptr_var_szoff_cst_size (size_t idx) void char_ptr_var_difoff_var_size (char *p, ptrdiff_t idx, size_t n) // { dg-message "at offset \\d+ into destination object 'p'" "note" { target *-*-* } .-1 } { - if (idx < DIFF_MAX - 3) - idx = DIFF_MAX - 3; + if (idx < DIFF_MAX - 4) + idx = DIFF_MAX - 4; if (n < 3 || 7 < n) n = 3; @@ -95,8 +95,8 @@ void char_ptr_var_difoff_var_size (char *p, ptrdiff_t idx, size_t n) void char_ptr_var_szoff_var_size (char *p, size_t idx, size_t n) // { dg-message "at offset \\\[\[1-9\]\[0-9\]+, \[1-9\]\[0-9\]+] into destination object 'p'" "note" { xfail *-*-* } .-1 } { - if (idx < DIFF_MAX - 3) - idx = DIFF_MAX - 3; + if (idx < DIFF_MAX - 4) + idx = DIFF_MAX - 4; if (n < 3 || 7 < n) n = 3; @@ -114,12 +114,15 @@ void char_ptr_var_szoff_var_size (char *p, size_t idx, size_t n) void int_ptr_cst_off_cst_size (int *p) - // { dg-message "at offset \[1-9\]\[0-9\]+ into destination object 'p'" "note" { target *-*-* } .-1 } + // { dg-message "at offset \\d+ into destination object 'p'" "note" { target *-*-* } .-1 } { size_t idx = DIFF_MAX / sizeof *p; - memset (p + idx, 0, 3); + memset (p + idx, 0, 1); sink (p); - memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" } + memset (p + idx, 0, 2); + sink (p); + + memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 2" } } diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-54.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-54.c index f5929c9e7d6..4bb3b06387f 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-54.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-54.c @@ -18,7 +18,7 @@ void char_flexarray_cst_off_cst_size (void) caxcc; // { dg-message "at offset \[1-9\]\[0-9\]+ into destination object 'caxcc'" "note" } char *p = caxcc.a; - size_t idx = DIFF_MAX - 4; + size_t idx = DIFF_MAX - 5; memset (p + idx, 0, 3); sink (p); @@ -42,8 +42,8 @@ void char_flexarray_var_off_cst_size (ptrdiff_t idx) char *p = caxvc.a; - if (idx < DIFF_MAX - 4) - idx = DIFF_MAX - 4; + if (idx < DIFF_MAX - 5) + idx = DIFF_MAX - 5; memset (p + idx, 0, 3); sink (p); @@ -59,8 +59,8 @@ void char_flexarray_var_off_var_size (size_t n, ptrdiff_t idx) char *p = caxvv.a; - if (idx < DIFF_MAX - 4) - idx = DIFF_MAX - 4; + if (idx < DIFF_MAX - 5) + idx = DIFF_MAX - 5; if (n < 3 || 7 < n) n = 3; @@ -76,10 +76,10 @@ void char_flexarray_var_off_var_size (size_t n, ptrdiff_t idx) void alloc_array_var_off_cst_size (size_t n, ptrdiff_t idx) { struct { char n, a[]; } - *p = __builtin_malloc (n); // { dg-message "at offset \\d+ into destination object" "note" } + *p = __builtin_malloc (n); // { dg-message "at offset \\\[\\d+, \\d+] into destination object" "note" } - if (idx < DIFF_MAX - 4) - idx = DIFF_MAX - 4; + if (idx < DIFF_MAX - 5) + idx = DIFF_MAX - 5; memset (p->a + idx, 0, 3); sink (p); @@ -91,13 +91,14 @@ void alloc_array_var_off_cst_size (size_t n, ptrdiff_t idx) void int_array_cst_off_cst_size (void) { extern struct { int n, a[]; } - iaxc; // { dg-message "at offset \[1-9\]\[0-9\]+ into destination object 'iaxc'" "note" } + iaxc; // { dg-message "at offset \\d+ into destination object 'iaxc'" "note" } int *p = iaxc.a; size_t idx = DIFF_MAX / sizeof *p - 1; - memset (p + idx, 0, 3); + memset (p + idx, 0, 2); sink (p); - memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" } + memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 2" } + sink (p); } diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c index 318d9bd1f94..ff2ab8d832f 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c @@ -39,9 +39,9 @@ void test_min (void) memset (q, 0, INT_MAX); // { dg-warning "writing 2147483647 bytes into a region of size 2147483646" "ilp32" { target ilp32 } .-1 } memset (q, 0, DIFF_MAX - 2); - memset (q, 0, DIFF_MAX); - // { dg-warning "writing 2147483647 bytes into a region of size 2147483646" "ilp32" { target ilp32 } .-1 } - // { dg-warning "writing 9223372036854775807 bytes into a region of size 9223372036854775806" "lp64" { target lp64 } .-2 } + memset (q, 0, DIFF_MAX - 1); + // { dg-warning "writing 2147483646 bytes into a region of size 2147483645" "ilp32" { target ilp32 } .-1 } + // { dg-warning "writing 9223372036854775806 bytes into a region of size 9223372036854775805" "lp64" { target lp64 } .-2 } } { diff --git a/gcc/testsuite/gcc.dg/Wstringop-overread-2.c b/gcc/testsuite/gcc.dg/Wstringop-overread-2.c index 16dc06d968b..8a42f6680b1 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overread-2.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overread-2.c @@ -25,11 +25,15 @@ void sink (int, ...); NOIPA void test_memchr (const void *p, int x) { + /* The size of the largest possible object cannot exceed PTRDIFF_MAX - 1 + so that the difference between a pointer just past its last byte and + the first byte doesn't is at most PTRDIFF_MAX. */ size_t dmax = PTRDIFF_MAX; size_t smax = SIZE_MAX; - T (memchr (p, x, dmax)); + T (memchr (p, x, dmax - 1)); + T (memchr (p, x, dmax)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (memchr (p, x, dmax + 1)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (memchr (p, x, dmax * 2)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (memchr (p, x, smax)); // { dg-warning "\\\[-Wstringop-overread" } @@ -41,8 +45,9 @@ NOIPA void test_memcmp (const void *p, const void *q) size_t dmax = PTRDIFF_MAX; size_t smax = SIZE_MAX; - T (memcmp (p, q, dmax)); + T (memcmp (p, q, dmax - 1)); + T (memcmp (p, q, dmax)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (memcmp (p, q, dmax + 1)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (memcmp (p, q, dmax * 2)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (memcmp (p, q, smax)); // { dg-warning "\\\[-Wstringop-overread" } @@ -54,9 +59,10 @@ NOIPA void test_memcpy (void *p, const void *q) size_t dmax = PTRDIFF_MAX; size_t smax = SIZE_MAX; - T (memcpy (p, q, dmax)); + T (memcpy (p, q, dmax - 1)); - T (memcpy (p, q, dmax + 1)); // -Wstringop-overflow disabled + T (memcpy (p, q, dmax)); // -Wstringop-overflow disabled + T (memcpy (p, q, dmax + 1)); // ditto T (memcpy (p, q, dmax * 2)); // ditto T (memcpy (p, q, smax)); // ditto } @@ -67,8 +73,9 @@ NOIPA void test_strncmp (const char *p, const char *q) size_t dmax = PTRDIFF_MAX; size_t smax = SIZE_MAX; - T (strncmp (p, q, dmax)); + T (strncmp (p, q, dmax - 1)); + T (strncmp (p, q, dmax)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" "strncmp" } T (strncmp (p, q, dmax + 1)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" "strncmp" } T (strncmp (p, q, dmax * 2)); // { dg-warning "\\\[-Wstringop-overread" "strncmp" } T (strncmp (p, q, smax)); // { dg-warning "\\\[-Wstringop-overread" "strncmp" } @@ -79,8 +86,9 @@ NOIPA void test_strncat (char *p, const char *q) size_t dmax = PTRDIFF_MAX; size_t smax = SIZE_MAX; - T (strncat (p, q, dmax)); + T (strncat (p, q, dmax - 1)); + T (strncat (p, q, dmax)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (strncat (p, q, dmax + 1)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (strncat (p, q, dmax * 2)); // { dg-warning "\\\[-Wstringop-overread" } T (strncat (p, q, smax)); // { dg-warning "\\\[-Wstringop-overread" } @@ -98,7 +106,8 @@ NOIPA void test_strncpy (char *p, const char *q) T (strncpy (p, q, dmax)); - T (strncpy (p, q, dmax + 1)); // -Wstringop-overflow disabled + T (strncpy (p, q, dmax)); // -Wstringop-overflow disabled + T (strncpy (p, q, dmax + 1)); // ditto T (strncpy (p, q, dmax * 2)); // ditto T (strncpy (p, q, smax)); // ditto #endif @@ -109,8 +118,9 @@ NOIPA void test_strnlen (const char *p) size_t dmax = PTRDIFF_MAX; size_t smax = SIZE_MAX; - T (strnlen (p, dmax)); + T (strnlen (p, dmax - 1)); + T (strnlen (p, dmax)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (strnlen (p, dmax + 1)); // { dg-warning "specified bound \[0-9\]+ exceeds maximum object size" } T (strnlen (p, dmax * 2)); // { dg-warning "\\\[-Wstringop-overread" } T (strnlen (p, smax)); // { dg-warning "\\\[-Wstringop-overread" } diff --git a/gcc/testsuite/gcc.dg/attr-nonstring-2.c b/gcc/testsuite/gcc.dg/attr-nonstring-2.c index ba4757d673f..20e3fa7772d 100644 --- a/gcc/testsuite/gcc.dg/attr-nonstring-2.c +++ b/gcc/testsuite/gcc.dg/attr-nonstring-2.c @@ -27,7 +27,8 @@ void test_strnlen_array_cst (void) T (strnlen (ns3, 2)); T (strnlen (ns3, 3)); T (strnlen (ns3, 4)); /* { dg-warning "specified bound 4 exceeds source size 3" } */ - T (strnlen (ns3, DIFF_MAX)); /* { dg-warning "specified bound \[0-9\]+ exceeds source size" } */ + T (strnlen (ns3, DIFF_MAX - 1)); /* { dg-warning "specified bound \[0-9\]+ exceeds source size" } */ + T (strnlen (ns3, DIFF_MAX)); /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */ T (strnlen (ns3, SIZE_MAX)); /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */ NONSTRING char ns5[5]; @@ -38,7 +39,8 @@ void test_strnlen_array_cst (void) T (strnlen (ns5, 2)); T (strnlen (ns5, 3)); T (strnlen (ns5, 6)); /* { dg-warning "specified bound 6 exceeds source size 5" } */ - T (strnlen (ns5, DIFF_MAX)); /* { dg-warning "specified bound \[0-9\]+ exceeds source size 5" } */ + T (strnlen (ns5, DIFF_MAX - 1)); /* { dg-warning "specified bound \[0-9\]+ exceeds source size 5" } */ + T (strnlen (ns5, DIFF_MAX)); /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */ T (strnlen (ns5, SIZE_MAX)); /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */ } @@ -53,7 +55,8 @@ void test_strnlen_array_range (void) T (strnlen (ns3, UR (3, 4))); T (strnlen (ns3, UR (3, DIFF_MAX))); T (strnlen (ns3, UR (4, 5))); /* { dg-warning "specified bound \\\[4, 5] exceeds source size 3" } */ - T (strnlen (ns3, UR (DIFF_MAX, SIZE_MAX))); /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds source size 3 " } */ + T (strnlen (ns3, UR (DIFF_MAX - 1, SIZE_MAX))); /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds source size 3 " } */ + T (strnlen (ns3, UR (DIFF_MAX, SIZE_MAX))); /* { dg-warning "specified bound \\\[\[0-9\]+, \[0-9\]+] exceeds maximum object size " } */ } @@ -98,7 +101,7 @@ void test_strnlen_string_cst (void) T (/* [] */, "1", 2, DIFF_MAX); T (/* [] */, "1", 2, SIZE_MAX); - size_t n = DIFF_MAX; + size_t n = DIFF_MAX - 1; T (/* [] */, "123", 3, n); T (/* [] */, "123", 3, n + 1); /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size " } */ n = SIZE_MAX; diff --git a/gcc/testsuite/gcc.dg/attr-nonstring-3.c b/gcc/testsuite/gcc.dg/attr-nonstring-3.c index 34f31fb6aa7..3eb80238b60 100644 --- a/gcc/testsuite/gcc.dg/attr-nonstring-3.c +++ b/gcc/testsuite/gcc.dg/attr-nonstring-3.c @@ -32,7 +32,10 @@ void sink (int); void strncmp_cst (void) { - size_t n = DIFF_MAX; + /* The largest object is DIFF_MAX - 1 bytes so that the difference + between a pointer just past the last byte and the first is no + more than DIFF_MAX. */ + size_t n = DIFF_MAX - 1; T (STR, /* [] */, STR, /* [] */, n); T (STR, /* [] */, STR, /* [] */, n + 1); /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */ @@ -84,7 +87,7 @@ void strncmp_cst (void) void strncmp_range (void) { - size_t n = DIFF_MAX; + size_t n = DIFF_MAX - 1; n = UR (n, n + 1); T (STR, /* [] */, STR, /* [] */, n); diff --git a/gcc/testsuite/gcc.dg/attr-nonstring-4.c b/gcc/testsuite/gcc.dg/attr-nonstring-4.c index f2416c16e83..641e2ca20a0 100644 --- a/gcc/testsuite/gcc.dg/attr-nonstring-4.c +++ b/gcc/testsuite/gcc.dg/attr-nonstring-4.c @@ -29,7 +29,10 @@ void sink (size_t); void strnlen_cst (void) { - size_t n = DIFF_MAX; + /* The largest object is DIFF_MAX - 1 bytes so that the difference + between a pointer just past the last byte and the first is no + more than DIFF_MAX. */ + size_t n = DIFF_MAX - 1; T (STR, /* [] */, n); T (STR, /* [] */, n + 1); /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */ @@ -47,7 +50,7 @@ void strnlen_cst (void) void strnlen_range (void) { - size_t n = DIFF_MAX; + size_t n = DIFF_MAX - 1; n = UR (n, n + 1); T (STR, /* [] */, n); diff --git a/gcc/testsuite/gcc.dg/strlenopt-40.c b/gcc/testsuite/gcc.dg/strlenopt-40.c index 7a97ebb8fe5..f9fcf7a0404 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-40.c +++ b/gcc/testsuite/gcc.dg/strlenopt-40.c @@ -118,17 +118,15 @@ void elim_global_arrays (int i) /* Even when treating a multi-dimensional array as a single string the length must be less DIFF_MAX - (ax_3[i] - ax_3[0]) but GCC doesn't do that computation yet so avoid testing it. */ - ELIM_TRUE (strlen (ax_3[0]) < DIFF_MAX); - ELIM_TRUE (strlen (ax_3[1]) < DIFF_MAX); - ELIM_TRUE (strlen (ax_3[9]) < DIFF_MAX); - ELIM_TRUE (strlen (ax_3[i]) < DIFF_MAX); + ELIM_TRUE (strlen (ax_3[0]) < DIFF_MAX - 1); + ELIM_TRUE (strlen (ax_3[1]) < DIFF_MAX - 1); + ELIM_TRUE (strlen (ax_3[9]) < DIFF_MAX - 1); + ELIM_TRUE (strlen (ax_3[i]) < DIFF_MAX - 1); ELIM_TRUE (strlen (a3) < sizeof a3); ELIM_TRUE (strlen (a7) < sizeof a7); - ELIM_TRUE (strlen (ax) != DIFF_MAX); - /* ELIM_TRUE (strlen (ax) != DIFF_MAX - 1); */ - /* ELIM_TRUE (strlen (ax) < DIFF_MAX - 1); */ + ELIM_TRUE (strlen (ax) != DIFF_MAX - 1); } void elim_pointer_to_arrays (void) @@ -137,21 +135,21 @@ void elim_pointer_to_arrays (void) to a smaller array to point to an object of a bigger type so the strlen range optimization must assume each array pointer points effectively to an array of an unknown bound. */ - ELIM_TRUE (strlen (*pa7) < DIFF_MAX); - ELIM_TRUE (strlen (*pa5) < DIFF_MAX); - ELIM_TRUE (strlen (*pa3) < DIFF_MAX); + ELIM_TRUE (strlen (*pa7) < DIFF_MAX - 1); + ELIM_TRUE (strlen (*pa5) < DIFF_MAX - 1); + ELIM_TRUE (strlen (*pa3) < DIFF_MAX - 1); - ELIM_TRUE (strlen ((*pa7_3)[0]) < DIFF_MAX); - ELIM_TRUE (strlen ((*pa7_3)[1]) < DIFF_MAX); - ELIM_TRUE (strlen ((*pa7_3)[6]) < DIFF_MAX); + ELIM_TRUE (strlen ((*pa7_3)[0]) < DIFF_MAX - 1); + ELIM_TRUE (strlen ((*pa7_3)[1]) < DIFF_MAX - 1); + ELIM_TRUE (strlen ((*pa7_3)[6]) < DIFF_MAX - 1); - ELIM_TRUE (strlen ((*pax_3)[0]) < DIFF_MAX); - ELIM_TRUE (strlen ((*pax_3)[1]) < DIFF_MAX); - ELIM_TRUE (strlen ((*pax_3)[9]) < DIFF_MAX); + ELIM_TRUE (strlen ((*pax_3)[0]) < DIFF_MAX - 1); + ELIM_TRUE (strlen ((*pax_3)[1]) < DIFF_MAX - 1); + ELIM_TRUE (strlen ((*pax_3)[9]) < DIFF_MAX - 1); - ELIM_TRUE (strlen ((*pa5_7)[0]) < DIFF_MAX); - ELIM_TRUE (strlen ((*pa5_7)[1]) < DIFF_MAX); - ELIM_TRUE (strlen ((*pa5_7)[4]) < DIFF_MAX); + ELIM_TRUE (strlen ((*pa5_7)[0]) < DIFF_MAX - 1); + ELIM_TRUE (strlen ((*pa5_7)[1]) < DIFF_MAX - 1); + ELIM_TRUE (strlen ((*pa5_7)[4]) < DIFF_MAX - 1); } void elim_global_arrays_and_strings (int i) @@ -258,9 +256,9 @@ void keep_global_arrays (int i) KEEP (strlen (a7 + i) < 2); /* The length of an array of unknown size may be as large as - DIFF_MAX - 2. */ - KEEP (strlen (ax) != DIFF_MAX - 2); - KEEP (strlen (ax) < DIFF_MAX - 2); + DIFF_MAX - 3. */ + KEEP (strlen (ax) != DIFF_MAX - 3); + KEEP (strlen (ax) < DIFF_MAX - 3); KEEP (strlen (ax) < 999); KEEP (strlen (ax) < 1); } @@ -396,26 +394,26 @@ void keep_member_arrays_ptr (struct MemArrays0 *ma0, /* Same as above. */ KEEP (strlen (ma0[i].a5_7[i]) > sizeof ma0[i].a5_7); - KEEP (strlen (ma0->a0) < DIFF_MAX - 2); + KEEP (strlen (ma0->a0) < DIFF_MAX - 3); KEEP (strlen (ma0->a0) < 999); KEEP (strlen (ma0->a0) < 1); - KEEP (strlen (max->ax) < DIFF_MAX - 2); + KEEP (strlen (max->ax) < DIFF_MAX - 3); KEEP (strlen (max->ax) < 999); KEEP (strlen (max->ax) < 1); - KEEP (strlen (ma7->a7) < DIFF_MAX - 2); + KEEP (strlen (ma7->a7) < DIFF_MAX - 3); KEEP (strlen (ma7->a7) < 999); KEEP (strlen (ma7->a7) < 1); } void keep_pointers (const char *s) { - KEEP (strlen (ptr) < DIFF_MAX - 2); + KEEP (strlen (ptr) < DIFF_MAX - 3); KEEP (strlen (ptr) < 999); KEEP (strlen (ptr) < 1); - KEEP (strlen (s) < DIFF_MAX - 2); + KEEP (strlen (s) < DIFF_MAX - 3); KEEP (strlen (s) < 999); KEEP (strlen (s) < 1); } diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index b84ad2b2d55..66a7f8b5a5d 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -1852,10 +1852,9 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound) src = gimple_assign_rhs1 (def); } - /* The longest string is PTRDIFF_MAX - 1 bytes including the final - NUL so that the difference between a pointer to just past it and - one to its beginning is positive. */ - wide_int max = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node)) - 2; + /* The longest string is MAX_OBJECT_SIZE - 1 bytes including the final + NUL. */ + wide_int max = wi::shwi (param_max_object_size - 1, TYPE_PRECISION (sizetype)); if (TREE_CODE (src) == ADDR_EXPR) { @@ -3933,7 +3932,7 @@ get_len_or_size (gimple *stmt, tree arg, int idx, /* The longest string in this data model. */ const unsigned HOST_WIDE_INT lenmax - = tree_to_uhwi (max_object_size ()) - 2; + = tree_to_uhwi (max_object_size ()) - 1; if (maxbound == HOST_WIDE_INT_M1U) { diff --git a/gcc/tree.c b/gcc/tree.c index 1ad4ad5a5f7..051bfb1fbfc 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -15319,13 +15319,20 @@ const builtin_structptr_type builtin_structptr_types[6] = { const_fexcept_t_ptr_type_node, const_ptr_type_node, "fexcept_t" } }; -/* Return the maximum object size. */ +/* Return the maximum object size, either set by --param max-object-size, + or PTRDIFF_MAX - 1. Minus 1 because the positive difference between + a pointer just past the last byte of the object and one to the first + cannot be greater than PTRDIFF_MAX. */ tree max_object_size (void) { - /* To do: Make this a configurable parameter. */ - return TYPE_MAX_VALUE (ptrdiff_type_node); + if (param_max_object_size < HOST_WIDE_INT_MAX) + return build_int_cst (sizetype, param_max_object_size); + + tree ptrdiff_max = TYPE_MAX_VALUE (ptrdiff_type_node); + unsigned HOST_WIDE_INT max = tree_to_uhwi (ptrdiff_max) - 1; + return build_int_cst (sizetype, max); } /* A wrapper around TARGET_VERIFY_TYPE_CONTEXT that makes the silent_p diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-64.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-64.c new file mode 100644 index 00000000000..074fc2a8397 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-64.c @@ -0,0 +1,19 @@ +/* Verify that --param max-object-size is recognized and respected. + { dg-do compile } + { dg-options "-O -Wall --param max-object-size=123" } */ + +typedef __SIZE_TYPE__ size_t; + +void* memset (void*, int, size_t); + +void sink (void*); + +void test_memset (void *p) +{ + memset (p, 0, 123); + memset (p, 0, 124); + // { dg-warning "specified bound 124 exceeds maximum object size 123 " "" { target *-*-* } .-1 } + // { dg-message "set by '--param max-object-size=123'" "note" { target *-*-* } .-2 } + sink (p); + memset (p, 0, 125); // { dg-warning "\\\[-Wstringop-overflow" } +}