Am Montag, dem 14.08.2023 um 11:51 +0200 schrieb Alejandro Colomar via Gcc: > Hi Richard, > > On 2023-08-14 08:41, Richard Biener wrote: > > On Fri, Aug 11, 2023 at 8:30 PM Alejandro Colomar via Gcc > > <gcc@gcc.gnu.org> wrote: > > [...] > > > > How about some -Wfam-sizeof-arithmetic that would not warn about taking > > > sizeof(s) but would warn if that sizeof is used in any arithmetic? > > > > There are probably many ways sizeof() plus arithmetic can yield a correct > > size for allocation. After all _all_ uses of FAM requires allocation > > and there's > > no convenient standard way of calculating the required size (sizeof > > (fam-type[n])?). > > You may be confusing sizeof(struct contains_fam) with sizeof(fam[n]). > > Yes, the second is necessary for allocation, but the first is not. Well, > it is valid for allocation but only because allocating extra bytes is not > a problem. > > The size of a flexible structure is calculated as the sum of the offset > of the fam, and the size of the fam. The size of the structure has nothing > to do. > > struct s { > int i; > char c; > char fam[]; > } s; > > size = offsetof(struct s, fam) + sizeof("foobar")); // OK: 12 B > > size = sizeof(struct s) + sizeof("foobar")); // NOK: 15 B; wastes bytes > ^~~~ problem here. >
The first formula may give a result smaller than sizeof(struct s), so could also be dangerous. Martin > > > > Iff we want to diagnose anything then possibly a computation that looks like > > a size computation but that's actually smaller than required, > > It's actually the other way around. The problem is that the computation may > give a value larger than the expected one. This can be usually a benign bug > and nothing bad will happen. But when a programmer relies on that size for > reading or writing, which I've seen happen, you better make sure that the > structure has no padding, or you'll be reading/writing at `fam + padding`. > > Example, using the allocation above: > > strcpy((char *) s + sizeof(struct s), "foobar"); // NOK, writes after > padding > puts(s->fam); // OK, reads the fam, but surprise > > // Unpredictable; prints 3 uninitialized bytes, then (if no previous > '\0') "foobar" > > strcpy(s->fam, "foobar"); // OK, writes at the fam > puts((char *) s + sizeof(struct s)); // NOK, reads after padding > > // prints: "bar" > > strcpy(s->fam, "foobar"); // OK > puts((char *) s + offsetof(struct s, fam)); // OK; with offsetof, > equivalent to s->fam > > // prints: "foobar" > > strcpy((char *) s + offsetof(struct s, fam), "foobar"); // Also OK > puts(s->fam); // OK > > // prints: "foobar" > > > but > > other than that - what > > would you suggest to fix such reported warnings? > > To fix the warnings, replace all invocations of `sizeof(struct contains_fam)` > by `offsetof(struct contains_fam, fam)`. > > Cheers, > Alex >