> On Jul 31, 2023, at 1:07 PM, Siddhesh Poyarekar <siddh...@gotplt.org> wrote: > > On 2023-07-31 13:03, Siddhesh Poyarekar wrote: >> On 2023-07-31 12:47, Qing Zhao wrote: >>> Hi, Sid and Jakub, >>> >>> I have a question in the following source portion of the routine >>> “addr_object_size” of gcc/tree-object-size.cc: >>> >>> 743 bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var); >>> 744 if (bytes != error_mark_node) >>> 745 { >>> 746 bytes = size_for_offset (var_size, bytes); >>> 747 if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == >>> MEM_REF) >>> 748 { >>> 749 tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, >>> 0), >>> 750 pt_var); >>> 751 if (bytes2 != error_mark_node) >>> 752 { >>> 753 bytes2 = size_for_offset (pt_var_size, bytes2); >>> 754 bytes = size_binop (MIN_EXPR, bytes, bytes2); >>> 755 } >>> 756 } >>> 757 } >>> >>> At line 754, why we always use “MIN_EXPR” whenever it’s for OST_MINIMUM or >>> not? >>> Shall we use >>> >>> (object_size_type & OST_MINIMUM >>> ? MIN_EXPR : MAX_EXPR) >>> >> That MIN_EXPR is not for OST_MINIMUM. It is to cater for allocations like >> this: >> typedef struct >> { >> int a; >> } A; >> size_t f() >> { >> A *p = malloc (1); >> return __builtin_object_size (p, 0); > > Correction, that should be __builtin_object_size (p->a, 0).
Actually, it should be __builtin_object_size(p->a, 1). For __builtin_object_size(p->a,0), gcc always uses the allocation size for the whole object. GCC’s current behavior is: For the size of the whole object, GCC currently always uses the allocation size. And for the size in the sub-object, GCC chose the smaller one among the allocation size and the TYPE_SIZE. Is this correct behavior? thanks. Qing Please see the following small example to show the above behavior: ===== #include <stdint.h> #include <malloc.h> #define LENGTH 10 #define SIZE_BUMP 5 #define noinline __attribute__((__noinline__)) struct fix { size_t foo; int array[LENGTH]; }; #define expect(p, _v) do { \ size_t v = _v; \ if (p == v) \ __builtin_printf ("ok: %s == %zd\n", #p, p); \ else \ { \ __builtin_printf ("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ } \ } while (0); /* in the following function, malloc allocated more space than size of the struct fix. Then what's the correct behavior we expect the __builtin_object_size should have for the following? */ static struct fix * noinline alloc_buf_more () { struct fix *p; p = malloc(sizeof (struct fix) + SIZE_BUMP * sizeof (int)); /*when checking the observed access p->array, we have info on both observered allocation and observed access, A. from observed allocation (alloc_size): (LENGTH + SIZE_BUMP) * sizeof (int) B. from observed access (TYPE): LENGTH * sizeof (int) */ /* for MAXIMUM size in the whole object: currently, GCC always used the A. */ expect(__builtin_object_size(p->array, 0), (LENGTH + SIZE_BUMP) * sizeof(int)); /* for MAXIMUM size in the sub-object: currently, GCC chose the smaller one among these two: B. */ expect(__builtin_object_size(p->array, 1), LENGTH * sizeof(int)); return p; } /* in the following function, malloc allocated less space than size of the struct fix. Then what's the correct behavior we expect the __builtin_object_size should have for the following? */ static struct fix * noinline alloc_buf_less () { struct fix *p; p = malloc(sizeof (struct fix) - SIZE_BUMP * sizeof (int)); /*when checking the observed access p->array, we have info on both observered allocation and observed access, A. from observed allocation (alloc_size): (LENGTH - SIZE_BUMP) * sizeof (int) B. from observed access (TYPE): LENGTH * sizeof (int) */ /* for MAXIMUM size in the whole object: currently, GCC always used the A. */ expect(__builtin_object_size(p->array, 0), (LENGTH - SIZE_BUMP) * sizeof(int)); /* for MAXIMUM size in the sub-object: currently, GCC chose the smaller one among these two: B. */ expect(__builtin_object_size(p->array, 1), (LENGTH - SIZE_BUMP) * sizeof(int)); return p; } int main () { struct fix *p, *q; p = alloc_buf_more (); q = alloc_buf_less (); return 0; } When compile the above small testing case with upstream gcc with -fstrict-flex-array=1: /home/opc/Install/latest/bin/gcc -O -fstrict-flex-arrays=1 t28.c ok: __builtin_object_size(p->array, 0) == 60 ok: __builtin_object_size(p->array, 1) == 40 ok: __builtin_object_size(p->array, 0) == 20 ok: __builtin_object_size(p->array, 1) == 20 > >> } >> where the returned size should be 1 and not sizeof (int). The mode doesn't >> really matter in this case. >> HTH. >> Sid