On 6/9/23 22:39, Eric Blake wrote: > [Bah - I typed up a longer response, but lost it when accidentally > trying to send through the wrong SMTP server, so now I have to > remember what I had...] > > On Fri, Jun 09, 2023 at 02:45:56PM +0200, Laszlo Ersek wrote: >> On 6/9/23 04:17, Eric Blake wrote: >>> When I added structured replies to the NBD spec, I intentionally chose >>> a wire layout where the magic number and cookie overlap, even while >>> the middle member changes from uint32_t error to the pair uint16_t >>> flags and type. Based only on a strict reading of C rules on >>> effective types and compatible type prefixes, it's probably >>> questionable on whether my reliance on type aliasing to reuse cookie >>> from the same offset of a union, or even the fact that a structured >>> reply is built by first reading bytes into sbuf.simple_reply then >>> following up with only bytes into the tail of sbuf.sr.structured_reply >>> is strictly portable. But since it works in practice, it's worth at >>> least adding some compile- and run-time assertions that our (ab)use of >>> aliasing is accessing the bytes we want under the types we expect. >>> Upcoming patches will restructure part of the sbuf layout to hopefully >>> be a little easier to tie back to strict C standards. >>> >>> Suggested-by: Laszlo Ersek <ler...@redhat.com> >>> Signed-off-by: Eric Blake <ebl...@redhat.com> >>> --- >>> generator/states-reply.c | 17 +++++++++++++---- >>> generator/states-reply-structured.c | 13 +++++++++---- >>> 2 files changed, 22 insertions(+), 8 deletions(-) >>> >>> diff --git a/generator/states-reply.c b/generator/states-reply.c >>> index 511e5cb1..2c77658b 100644 >>> --- a/generator/states-reply.c >>> +++ b/generator/states-reply.c >>> @@ -17,6 +17,7 @@ >>> */ >>> >>> #include <assert.h> >>> +#include <stddef.h> >>> >>> /* State machine for receiving reply messages from the server. >>> * >>> @@ -63,9 +64,15 @@ REPLY.START: >>> ssize_t r; >>> >>> /* We read all replies initially as if they are simple replies, but >>> - * check the magic in CHECK_SIMPLE_OR_STRUCTURED_REPLY below. >>> - * This works because the structured_reply header is larger. >>> + * check the magic in CHECK_SIMPLE_OR_STRUCTURED_REPLY below. This >>> + * works because the structured_reply header is larger, and because >>> + * the last member of a simple reply, cookie, is coincident between >>> + * the two structs (an intentional design decision in the NBD spec >>> + * when structured replies were added). >>> */ >>> + STATIC_ASSERT (offsetof (struct nbd_handle, sbuf.simple_reply.cookie) == >>> + offsetof (struct nbd_handle, >>> sbuf.sr.structured_reply.cookie), >>> + cookie_aliasing); >> >> Can you perhaps append >> >> ... && >> sizeof h->sbuf.simple_reply.cookie == >> sizeof h->sbuf.sr.structured_reply.cookie >> >> (if you agree)? > > Yes, that makes sense, and I did so for what got pushed as 29342fedb53 > >> >> Also, the commit message and the comment talk about the magic number as >> well, not just the cookie, and the static assertion ignores magic. >> However, I can see the magic handling changes in the next patch. > > I was a bit less concerned about magic (it is easy to see that it is > at offset 0 in both types and could satisfy the common prefix rules, > while seeing cookie's location and a non-common prefix makes the > latter more imporant to assert). But checking two members instead of > one shouldn't hurt, and in fact, once extended types are in (plus > patch 4/4 of this series also adds an anonymous sub-struct in 'union > reply_header' which is also worth validating), it may make sense to do > a followup patch that adds: > > #define ASSERT_MEMBER_OVERLAP(TypeA, memberA, TypeB, memberB) \ > STATIC_ASSERT (offsetof (TypeA, memberA) == offsetof (TypeB, memberB) && \ > sizeof ((TypeA *)NULL)->memberA == sizeof ((TypeB > *)NULL)->memberB, \ > member_overlap) > > to be used either as: > > ASSERT_MEMBER_OVERLAP (struct nbd_simple_reply, cookie, > struct nbd_structured_reply, cookie); > > or as > > ASSERT_MEMBER_OVERLAP (struct nbd_handle, sbuf.simple_reply.magic, > struct nbd_handle, sbuf.sr.structured_reply.magic); > > Would it make sense to have the macro take only three arguments (since > both of those invocations repeat an argument); if so, is it better to > share the common type name, or the common member name?
Both 4-arg invocations look fine to me, so I wouldn't push for a 3-arg variant at this time. > I also note that our "static-assert.h" file defines STATIC_ASSERT() as > a do/while statement (that is, it MUST appear inside a function body, > so we can't use it easily in .h files); contrast that with C11's > _Static_assert() or qemu's QEMU_BUILD_BUG_ON() that behave more as a > type declaration (and can therefore appear outside of a function body; > C23 will take it one step further by adding static_assert(expr) > alongside static_assert(expr, msg). I consider myself too tainted, > not only by helping with qemu's implementation, but also by reviewing > gnulib's implementation (which uses __VA_ARGS__ to emulate C23 > semantics of an optional message), to be able to feel comfortable > trying to improve our static-assert.h for sharing back to nbdkit, but > I don't mind reviewing anyone else's attempts. I don't recall feeling a need to use a static assertion outside of a function body. My gut feeling is that any given assertion (static or runtime) tends to matter, in the end, for a specific statement; the statement where we "exploit" the particular predicate. If the predicate is supposed to be evaluated at compile time, that may allow for moving the static assertion to a header file, but I'm not convinced it helps readability and/or whether such a code movement is really necessary. For now I feel OK with just sticking our current STATIC_ASSERT(). Laszlo _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://listman.redhat.com/mailman/listinfo/libguestfs