Strict alias violation or alignment violation with a struct with flexible array member?

匿名 (未验证) 提交于 2019-12-03 01:36:02

问题:

Imagine a structure like this:

struct test_s {     int i;     size_t namelen;     char name[]; };

Now I would like to return an array of such structures to user code, also using a generic function which takes a void * pointer:

size_t test_read(void *buf, size_t bufsize);

Each of the array elements would need to aligned to struct s_s alignment. In each of array element the namelen is adjusted, so it is greater or equal then strlen(name), but with additional "unused" bytes in between array members, so that next array member starts at memory bank dividable by alignof(struct s_s).

So we can know/assert that having any struct test_s *t it is true that t->namelen % alignof(struct test_s) == 0 and t->namelen == 0 || t->namelen >= strlen(t->name).

Now image that test_read returns 4 of struct test_s structures. We can iterate through them, but adding each loop the sizeof(struct test_s) and adding the t->namelen of the current already processed member pnt += sizeof(struct test_s) + t->namelen. The "unused" "padding" bytes between array members and strings are left uninitialized and the intention is that they are never to be accessed.

#include <stdio.h> #include <stddef.h> #include <assert.h> #include <string.h> #include <stdlib.h> #include <stdint.h> #include <stdalign.h>  // out structure struct test_s {     int i;     size_t namelen;     char name[]; };  // stores an struct test_s object into buf and after it stores string as pointed to by name // returns sizeof(struct test_s) + strlen(name) size_t test_init(void *buf, size_t bufsize,      int i, const char name[])  {     assert(buf != NULL);     assert(bufsize > sizeof(struct test_s));     size_t namelen;     // if (t->namelen == 0) { that means that t->name is empty. }     if (name) {         namelen = strlen(name) + 1;         assert(bufsize > sizeof(struct test_s) + namelen * sizeof(*((struct test_s*)0)->name));     } else {         namelen = 0;     }      struct test_s * const t = buf;     t->i = i;     t->namelen = namelen;     memcpy(t->name, name, namelen);      return sizeof(*t) + namelen * sizeof(*t->name);    }  // works as test_init, but returned value is incremented to // make the `buf + returned value` aligned to struct test_s size_t test_init_aligned(void *buf, size_t bufsize,      int i, const char name[])  {     const size_t copied = test_init(buf, bufsize, i, name);      // align the end of the struct to be aligned with struct test_s     struct test_s * const t = buf;     const size_t tmp = copied % alignof(struct test_s);     const size_t to_aligned = tmp ? alignof(struct test_s) - tmp : 0;     t->namelen += to_aligned;     const size_t aligned_size = copied + to_aligned;     return aligned_size; }  // returns multiple struct test_s objects and stores them in buf // returns number of bytes written size_t test_read(void *buf, size_t bufsize) {     char * const outbeg = buf;     char *out = buf;     char * const outend = &out[bufsize];     out += test_init_aligned(out, outend - out, 1, "first element");     out += test_init_aligned(out, outend - out, 2, "second element");     out += test_init_aligned(out, outend - out, 3, "third element");     out += test_init_aligned(out, outend - out, 4, NULL);     return out - outbeg; }  int main() {     // our read buffer     char alignas(struct test_s) buf[1024];      // read structs test_s with strings into our buffer     const size_t readlen = test_read(buf, sizeof(buf));      const struct test_s *test = NULL;     const char *pnt = NULL;     for (pnt = &buf[0];             pnt < &buf[readlen];             pnt += sizeof(*test) + test->namelen * sizeof(*test->name)) {         test = (const struct test_s *)pnt;          printf("i=%d len=%2zu name='%s'\n",              test->i,             test->namelen,              test->namelen != 0 ? test->name : ""         );      } }
  1. Does this code has any strict aliasing violations?
  2. Does this code can unaligned access any objects?
  3. Does this code has any undefined behaviors?
  4. This code is based on the example in man 7 inotify and I intended for it to be very similar. The example there iterates over struct inotify_events using the same principle. Does this example has any undefined behaviours?

I say there is no strict aliasing violation. I never access an underlying object using different pointers, the pointers are always struct test_s* and char*, although arithmetic is done using char* pointers.

Live version of the code available at onlinegdb.

The question originates from the comments from this question.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!