[cfe-dev] array bounds checking, especially with the strcmp built-in

Fabian Frank fabian.frank.de at gmail.com
Fri Nov 1 18:00:23 PDT 2013


Hi Guys,


I am compiling a codebase with clang 3.4 (Ubuntu clang version 3.4-1ubuntu1 (trunk) (based on LLVM 3.4)) for the first time and trying to get the benefits of its array bounds checking feature. At one point the following in dirent.h
strcut dirent {
  …
 char d_name[0]
}
combined with a strcmp (“foobar”, some_dirent.d_name); seems to trip clang, because of the variable length array. I thought that’s fine and disabled bounds checking for that particular strcmp. However, I also get errors for any strcmp where a comparison string is shorter than 3. For example things like
strcmp(myvar, “ok”);
cause the following error:
XXX.c:137:2070: error: array index 3 is past the end of the array (which contains 3 elements) [-Werror,-Warray-bounds]
 if (stat == ((void*)0) || __extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (stat) && __builtin_constant_p ("ok") && (__s1_len = __builtin_strlen (stat), __s2_len = __builtin_strlen ("ok"), (!((size_t)(const void *)((stat) + 1) - (size_t)(const void *)(stat) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("ok") + 1) - (size_t)(const void *)("ok") == 1) || __s2_len >= 4)) ? __builtin_strcmp (stat, "ok") : (__builtin_constant_p (stat) && ((size_t)(const void *)((stat) + 1) - (size_t)(const void *)(stat) == 1) && (__s1_len = __builtin_strlen (stat), __s1_len < 4) ? (__builtin_constant_p ("ok") && ((size_t)(const void *)(("ok") + 1) - (size_t)(const void *)("ok") == 1) ? __builtin_strcmp (stat, "ok") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("ok"); register int __result = (((const unsigned char *) (const char *) (stat))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (stat))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (stat))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (stat))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("ok") && ((size_t)(const void *)(("ok") + 1) - (size_t)(const void *)("ok") == 1) && (__s2_len = __builtin_strlen ("ok"), __s2_len < 4) ? (__builtin_constant_p (stat) && ((size_t)(const void *)((stat) + 1) - (size_t)(const void *)(stat) == 1) ? __builtin_strcmp (stat, "ok") : (__extension__ ({ const unsigned char *__s1 = (const unsigned char *) (const char *) (stat); register int __result = __s1[0] - ((const unsigned char *) (const char *) ("ok"))[0]; if (__s2_len > 0 && __result == 0) { __result = (__s1[1] - ((const unsigned char *) (const char *) ("ok"))[1]); if (__s2_len > 1 && __result == 0) { __result = (__s1[2] - ((const unsigned char *) (const char *) ("ok"))[2]); if (__s2_len > 2 && __result == 0) __result = (__s1[3] - ((const unsigned char *) (const char *) ("ok"))[3]); } } __result; }))) : __builtin_strcmp (stat, "ok")))); })) {

If I change this to
strcmp(myvar, “okX”);
it compiles fine. gcc 4.8.1 compiles both statements. I am worried that I might be missing something obvious here and start spraying diagnostic pragmas across my codebase for no reason.


Thank you for your help,
Fabian



More information about the cfe-dev mailing list