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

Jordan Rose jordan_rose at apple.com
Mon Nov 4 09:14:45 PST 2013


I can't reproduce this with a minimal test case:

> #include <string.h>
> 
> void test(const char *var) {
> 	strcmp(var, "ok");
> }

Can you please find a minimally-reproducing test case and file a bug at http://llvm.org/bugs/? Please include both original and preprocessed source.

Thanks,
Jordan


On Nov 1, 2013, at 18:00 , Fabian Frank <fabian.frank.de at gmail.com> wrote:

> 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
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev





More information about the cfe-dev mailing list