<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/60926>60926</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
-fsanitize=bounds missing bounds provided by __builtin_dynamic_object_size()
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
isanbard
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
kees
</td>
</tr>
</table>
<pre>
While `-fsanitize-bounds` is able to perform run-time bounds checking on fixed-size arrays (i.e. when `__builtin_object_size(x, 1)` does not return `SIZE_MAX`), it does not perform bounds checking when `__builtin_dynamic_object_size(x, 1)` is available.
For example, the attached program produces no bounds-checker warnings for the "dynamic size" case:
```
/* Build with -Wall -O2 -fstrict-flex-arrays=3 -fsanitize=bounds -fstrict-flex-arrays=3 */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define noinline __attribute__((__noinline__))
volatile int zero = 0; /* used to stop optimizer from seeing constant expressions. */
#define report_size(p) do { \
const size_t bdos = __builtin_dynamic_object_size(p, 1); \
\
if (__builtin_constant_p(bdos)) { \
if (bdos == SIZE_MAX) { \
printf("\n" #p " has unknowable size\n"); \
} else { \
printf("\n" #p " has a fixed size: %zu (%zu elements of size %zu)\n", bdos, \
bdos / sizeof(*(p)), sizeof(*(p))); \
} \
} else { \
printf("\n" #p " has a dynamic size: %zu (%zu elements of size %zu)\n", bdos, \
bdos / sizeof(*(p)), sizeof(*(p))); \
} \
} while (0)
#define report_assignment(p, index, expect) \
printf(#p "[%d] assignment: %d (should be %s)\n", index, (p)[index] = 0xFF, expect)
#define MAX_INDEX 16
struct fixed {
unsigned long flags;
size_t foo;
int array[MAX_INDEX];
};
/* should emit "fixed" */
static void noinline do_fixed(struct fixed *p, int index)
{
report_size(p->array);
report_assignment(p->array, 0, "ok");
report_assignment(p->array, index, "failure");
}
struct flex {
unsigned long flags;
size_t foo;
int array[];
};
/* should emit "dynamic" */
static void noinline do_dynamic(unsigned char count, int index)
{
/* malloc() is marked with __attribute__((alloc_size(1))) */
struct flex *p = malloc(sizeof(*p) + (zero + count) * sizeof(*p->array));
report_size(p->array);
report_assignment(p->array, 0, "ok");
report_assignment(p->array, index, "failure");
free(p);
}
/* should emit "unknowable" */
static void noinline do_unknown(struct flex *p, int index)
{
report_size(p->array);
report_assignment(p->array, 0, "ignored");
report_assignment(p->array, index, "ignored");
}
int main(int argc, char *argv[])
{
int a;
struct fixed f;
int b;
struct flex *p;
int index = MAX_INDEX + zero;
a = b = argc; /* wrap "f" with an extra int to catch overflow writes */
do_fixed(&f, index + a - b);
do_dynamic(index, index);
p = malloc(100);
do_unknown(p, index);
free(p);
return 0;
}
```
```
$ gcc -Wall -O2 -fstrict-flex-arrays=3 -fsanitize=bounds -fstrict-flex-arrays=3 -o bounds bounds.c
$ ./bounds
p->array has a fixed size: 64 (16 elements of size 4)
p->array[0] assignment: 255 (should be ok)
bounds.c:43:5: runtime error: index 16 out of bounds for type 'int[16]'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior bounds.c:43:5 in
p->array[16] assignment: 255 (should be failure)
p->array has a dynamic size: 64 (16 elements of size 4)
p->array[0] assignment: 255 (should be ok)
p->array[16] assignment: 255 (should be failure)
p->array has unknowable size
p->array[0] assignment: 255 (should be ignored)
p->array[16] assignment: 255 (should be ignored)
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0WE-P4joS_zTmUgoKDuHPgQM0g_QOsyvt6OnN7gU5sUP8OrEj2wG6P_3KdhISOvT0zJtGCJK4yvWrql-V7RCt-UkwtkHxDmHMNREJURRhjOL9hNQml2rzzJieJJK-bP7KecEALcIg00Rww19ZkMhaUI0WIXANJCkYGAkVU5lUJahaBIaXDLwUpDlLn7k4gRSQ8SujgeavDIhS5EUDwis-ZVO45ExYK8djUvPCcHGUyd8sNUcrjPDqivATzBBeW6tUMg1CGlDM1Mrpffvjf1-OX7ff0SK0QvgJuLnJtdjuIb21Sl8EKXn6nnXr85nwwjo-ReEehVv_e5AK2JWUVcGsvMkZEGNImjMKlZInRUr7T-vUwWrQBA4NU3AhSnBx0pBJ5ZQRxg0c8DgwpEQzFG37Vq3H_utv8QHhLexqXlC4cJND8BcpCgj-jSHItFE8NUFWsGvgM4CifQS33KJo3wTpoTDCzkhjLeIiLWrKAEVP2lAuzDRH0ZdHw_KdUcXF6eFwSYpCpv3hVoiyjAsGQnJR2IvjkRijeFIbdjwivEJ4dTy2o_bJ2n57c5xlQYxlORcGXpmSgKI9hCjaQRPNWjNqOa6NrEBWhpf8lSnIlCxBM2aplEqhDREG2LVSTGsuhZ4OY3UHWLFKqo5iFcJrcB8qAS139grFT17J3jgDjghHAwmV2qH8EXOrjrnWm_58gxuegQtTO1nrzbFCeGWN-ag5YAPFm3ILyaLqqvGNSqW4MJnLCkbxk7CkRjiqLNkhJxpq8SzkxTUV54KXGXPAObHcAys0GwdmPz80SHxX8taiLSAcv9bgFOwFK1jJhNEgMyfixy2eFtkT-AA9jQNoPj48-OAmkR7Qtsl707EejTx2fZjQ8Vh8IACDLvM5Ifit7g9ctzcXv0jhVXhX2m-qza9-1p22OLigzPV3dq1Yahxl-8Z68fNBc-tmTFG8h95sPmzUgtC5rAsKiQuUHsaps9Z6GO_8o3jvu871cBiAGffm6_b78Y9_7b98b8I7W_TltFF1ahpeo-Xu5kwt3OJPoZDiBFlBThpFvfGmvWRSDh7bxuhWABTvOtMo3ndCaNm77q9DTSxYyY2NnYPkGXhrjNoQw1M4S05vXZzKYyO8GrqDt03aTBvMNkado3edNUDRF4_ecenm1ignetJPEPpUYfncNaGfUe9lG2eEF7Vid_PYwI1krmDXn0jcB7L2K8lq2sJH09WJrzqwaU4UpLK2oXk_ZbaqPQi_0Lt6W9u9VknUM2u2MiNLu5NuUz3resYAsWN2P7J4W7lq62z1e0_l1e3iv_K7AbxrnXDzDjrVkF3jDHmfiB9koW_6Y1T8CR4-JiJkirX7kEfsHKfJbcX-KFO8huiVdpuVD9DkM2LKT0Iq15j-SWDHZ7mLofWuJNw67-vzlFp9VykIb4k6nZtyHfW-q-sBz_oEd10yuw1b6eShdBf4e4EuC65QbuuNLQZbFXcdpFUjTjxxv8632yb6oohbPzNLE1fORAC7GkWcMSMhJSbNQZ6Zygp5gYvihuk3lez3yN3qgPAi61Lh4BEIIBmkwOsOelSXuY5q4w7dNYpZGA4oMmBzNTpfO9NogQ0kmuNsOMKdu0Pe-MlvDqc0_e3nvaA9qTZ_0_Rmb4rwoXkb0AN2q5HRHfZiblvrbPF2YznvSN8rs3gXvt1r4TgebrVsW2x0O5jRdh6haBtbBVUL91aCKSWVfeD5MluArI0F0PjoDt8vld27LbkwKN7NFq4al37yb39-_br9z3_tDH8KvxujO5aTM5fqWxNUN3_djgZJMwxvgAEXMOKvs_gjh7s2vn439Pd7-88O_ic5cn8s_DWcXYf-ZbD3M9zV4IRuIrqO1mTCNrPFchmu18vVepJvZlG8xtl6Qcg8pOmKzhmNsvkyJGmYzNI4m_ANDnEUYozxLIzC9XQezzMaU4LTNEoZDdE8ZCXhxbQozuVUqtOEa12zzSJc48WkIAkrdPNOT7ALuMHmpZ7aWJ0gqU8azcOCa6NvsxhuCrYZ6wgl15qLU1sZlZJnThmF5OWHrx0QXk9qVWxyYyqNIr9zOJy4yetkmsoS4YMF0PwFlZJ_u-POwcHWCB-cW_8PAAD__9STBCc">