Created attachment 45958 [details] reduced test case I am using gcc 8.3.1 20190228 I got a strange warning on a memcmp call, it looks like gcc is tricked to believe the length is negative and that it overflows, or something like that ? Not sure. With "gcc -O -c memcmp-short.c" : memcmp-short.c: In function ‘f’: memcmp-short.c:9:12: warning: ‘memcmp’ specified size between 18446744071562067968 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Wstringop-overflow=] return memcmp(s1, s2, min); ^~~~~~~~~~~~~~~~~~~ This is only triggered with optimizations (-O). And only with gcc >= 8 according to godbolt. I think I will use a workaround similar to the one suggested in 89689 : if (min < 0) { __builtin_unreachable(); } Cheers !
Warning like this shouldn't be enabled by default with the amount of false positives it has. In this case, we have: # RANGE [-2147483648, 0] min_6 = MIN_EXPR <len1_5, 0>; # RANGE ~[1, 18446744071562067967] _3 = (long unsigned int) min_6; _7 = __builtin_memcmp (s1.0_1, "", _3); where we don't know anything about len1 (VARYING), but as we folded strlen ("") into 0, it is min is actually MIN (len1, 0) and so the range of it is indeed [-2147483648, 0] and that converted to size_t is 0 or -2147483648UL or higher. As a workaround, I'd strongly recommend not using int variables to hold sizes of strings, it should be using size_t instead.
The warning here is by design. When the value's range is negative and includes zero it's taken to be strictly negative because it's so much more likely. We could adjust this heuristic if we thought it necessary (simply by passing allow_zero = true to get_size_range()) but since as Jakub said the size would more appropriately be represented as unsigned (otherwise a large strlen result could result in min being negative), I don't believe it is. Thus this is not a false positive. The following is a simplified version of the test case. $ cat z.c && gcc -O2 -S -Wall -fdump-tree-vrp1=/dev/stdout z.c int f (const char *s1, const char *s2, int i) { int min = i < 0 ? i : 0; return __builtin_memcmp (s1, s2, min); } ;; Function f (f, funcdef_no=0, decl_uid=1908, cgraph_uid=1, symbol_order=0) ;; 1 loops found ;; ;; Loop 0 ;; header 0, latch 1 ;; depth 0, outer -1 ;; nodes: 0 1 2 ;; 2 succs { 1 } Value ranges after VRP: _1: long unsigned int ~[1, 18446744071562067967] i_2(D): VARYING min_3: int [-INF, 0] s1_5(D): VARYING s2_6(D): VARYING _7: VARYING f (const char * s1, const char * s2, int i) { int min; long unsigned int _1; int _7; <bb 2> [local count: 1073741824]: min_3 = MIN_EXPR <i_2(D), 0>; _1 = (long unsigned int) min_3; _7 = __builtin_memcmp (s1_5(D), s2_6(D), _1); return _7; } z.c: In function ‘f’: z.c:4:10: warning: ‘__builtin_memcmp’ specified size between 18446744071562067968 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Wstringop-overflow=] 4 | return __builtin_memcmp (s1, s2, min); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~