Should GCC warn about sizeof(flexible_struct)?

Alejandro Colomar alx@kernel.org
Mon Aug 14 09:51:34 GMT 2023


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.

> 
> 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

-- 
<http://www.alejandro-colomar.es/>
GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://gcc.gnu.org/pipermail/gcc/attachments/20230814/2749bd50/attachment.sig>


More information about the Gcc mailing list