[m-dev.] Spurious warnings with gcc -Warray-bounds

Julien Fischer jfischer at opturion.com
Fri Mar 4 17:56:34 AEDT 2022


Hi,

When compiling Mercury with GCC versions 9, 10 and 11, I currently get a
lot of warnings of the form:

     mercury_trace_term.c: In function ‘MR_cterm_is_nil’:
     mercury_trace_term.c:391:9: warning: array subscript 3 is outside array bounds of ‘const char[3]’ [-Warray-bounds]

This is occurring in both the handwritten and generated code.  The
culprit here appears to be GCC itself.

The code generating the warning is:

     if (MR_strdiff(term->MR_term_functor, "[]")) {
         return MR_FALSE;
     }

which expands to:

     if (strcmp(term->MR_term_functor, "[]")) {
         return MR_FALSE;
     }

and which GCC then expands into the following monstrosity:

  if ((__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(term->MR_term_functor) && __builtin_constant_p ("[]") && (__s1_len =
strlen (term->MR_term_functor), __s2_len = strlen ("[]"),
(!((size_t)(const void *)((term->MR_term_functor) + 1) - (size_t)(const
void *)(term->MR_term_functor) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("[]") + 1) - (size_t)(const void *)("[]") ==
1) || __s2_len >= 4)) ? __builtin_strcmp (term->MR_term_functor, "[]") :
(__builtin_constant_p (term->MR_term_functor) && ((size_t)(const void
*)((term->MR_term_functor) + 1) - (size_t)(const void
*)(term->MR_term_functor) == 1) && (__s1_len = strlen
(term->MR_term_functor), __s1_len < 4) ? (__builtin_constant_p ("[]") &&
((size_t)(const void *)(("[]") + 1) - (size_t)(const void *)("[]") == 1)
? __builtin_strcmp (term->MR_term_functor, "[]") : (__extension__ ({
const unsigned char *__s2 = (const unsigned char *) (const char *)
("[]"); int __result = (((const unsigned char *) (const char *)
(term->MR_term_functor))[0] - __s2[0]); if (__s1_len > 0 && __result ==
0) { __result = (((const unsigned char *) (const char *)
(term->MR_term_functor))[1] - __s2[1]); if (__s1_len > 1 && __result ==
0) { __result = (((const unsigned char *) (const char *)
(term->MR_term_functor))[2] - __s2[2]); if (__s1_len > 2 && __result ==
0) __result = (((const unsigned char *) (const char *)
(term->MR_term_functor))[3] - __s2[3]); } } __result; }))) :
(__builtin_constant_p ("[]") && ((size_t)(const void *)(("[]") + 1) -
(size_t)(const void *)("[]") == 1) && (__s2_len = strlen ("[]"),
__s2_len < 4) ? (__builtin_constant_p (term->MR_term_functor) &&
((size_t)(const void *)((term->MR_term_functor) + 1) - (size_t)(const
void *)(term->MR_term_functor) == 1) ? __builtin_strcmp
(term->MR_term_functor, "[]") : (__extension__ ({ const unsigned char
*__s1 = (const unsigned char *) (const char *) (term->MR_term_functor);
register int __result = __s1[0] - ((const unsigned char *) (const char
*) ("[]"))[0]; if (__s2_len > 0 && __result == 0) { __result = (__s1[1]
- ((const unsigned char *) (const char *) ("[]"))[1]); if (__s2_len > 1
   && __result == 0) { __result = (__s1[2] - ((const unsigned char *)
(const char *) ("[]"))[2]); if (__s2_len > 2 && __result == 0) __result
= (__s1[3] - ((const unsigned char *) (const char *) ("[]"))[3]); } }
__result; }))) : __builtin_strcmp (term->MR_term_functor, "[]")))); })
!= 0)) {
         return 0;
     }

It is the above that is triggering -Warray-bounds.
It seems that -Warray-bounds has a rich history of producing false
positives, see: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56456>.

I see a couple of options here:

1. We could redefine MR_strdiff and friends as follows:

     #define MR_streq(s1, s2) ((strcmp)(s1, s2) == 0)

and require that the actual strcmp() function be called.

2. We can turn of that warning for the affected versions of GCC.

Given that the are so many open false positives reported against that
warning, my preference would be for (2).

Julien.


More information about the developers mailing list