Messages in this thread | | | Date | Thu, 17 Aug 2023 02:23:21 +0200 | From | Alejandro Colomar <> | Subject | struct_size() using sizeof() vs offsetof() |
| |
Hi Kees, Gustavo,
I've been discussing with a friend about the appropriateness of sizeof() vs offsetof() for calculating the size of a structure with a flexible array member (FAM).
After reading Jens Gustedt's blog post about it[1], we tried some tests, and we got some interesting results that discouraged me from using sizeof(). See below.
But then, said friend pointed to me that the kernel uses sizeof() in struct_size(), and we wondered why you would have chosen it. It's safe as long as you _know_ that there's no padding, or that the alignment of the FAM is as large as the padding (which you probably know in the kernel), but it seems safer to use
MAX(sizeof(s), offsetof(s, fam) + sizeof_member(s, fam) * count)
The thing is, if there's any trailing padding in the struct, the FAM may overlap the padding, and the calculation with sizeof() will waste a few bytes, and if misused to get the location of the FAM, the problem will be bigger, as you'll get a wrong location.
So, I just wanted to pry what and especially why the kernel chose to prefer a simple sizeof().
Cheers, Alex
---
$ cat off.c #include <err.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
struct s { int i; char c; char fam[]; };
static inline void *xmalloc(size_t size);
int main(void) { char *p; struct s *s;
printf("sizeof: %zu\n", sizeof(struct s)); printf("offsetof: %zu\n", offsetof(struct s, fam));
puts("\nWith sizeof():");
s = xmalloc(sizeof(struct s) + sizeof("Hello, sizeof!")); strcpy(s->fam, "Hello, sizeof!"); p = (char *) s + sizeof(struct s); puts(p); free(s);
puts("\nWith offsetof(3):");
s = xmalloc(offsetof(struct s, fam) + sizeof("Hello, offsetof!")); strcpy(s->fam, "Hello, offsetof!"); p = (char *) s + offsetof(struct s, fam); puts(p); free(s);
exit(EXIT_SUCCESS); }
static inline void * xmalloc(size_t size) { void *p;
p = malloc(size); if (p == NULL) err(EXIT_FAILURE, "malloc"); return p; }
$ ./a.out sizeof: 8 offsetof: 5
With sizeof(): lo, sizeof!
With offsetof(3): Hello, offsetof!
[1]: <https://gustedt.wordpress.com/2011/03/14/flexible-array-member/> -- <http://www.alejandro-colomar.es/> GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5 [unhandled content-type:application/pgp-signature] | |