On 3/15/23 18:14, Eric Blake wrote: > On Wed, Mar 15, 2023 at 03:30:12PM +0100, Laszlo Ersek wrote: >> On 3/15/23 15:01, Eric Blake wrote: >> >>> [...] >> >> Thanks for the thorough review; I'm glad all the fine points I sought to >> put in the patch were received -- and well-received! :) >> >> One question: >> >>> The only change I recommend is the addition of the __attribute__; but >>> with or without it, I'm happy with: >> >> Do we have general rules on attribute usage in libnbd vs. nbdkit? >> >> The __sentinel__ (aka sentinel) attribute is used in nbdkit, but not yet >> in libnbd. Now, that could be happenstance, but it rhymes with another >> (obscure?) discrepancy in attribute usage. > > I think it's happenstance; until today, libnbd did not yet have a > varargs function where annotating the need for a NULL terminator was > useful to let the compiler aid in flagging erroneous usage. > >> >> Namely, when I was comparing the common/ subdirectories of both >> projects, I noticed that nbdkit used the cleanup attribute, and libnbd >> didn't. First I thought it was a mistake / oversight, but then I found a >> porting note from Rich, in libnbd commit f306e231d294 ("common/utils: >> Add extensible string, based on vector", 2022-03-12): >> >> RWMJ: This removes the CLEANUP_FREE_STRING macro since libnbd does not >> use __attribute__((cleanup)). >> >> and then again in f3828bfd42be ("common/utils: Add new string vector >> types", 2022-03-12): >> >> RWMJ: Removed the CLEANUP_* macros. >> > > Most attributes are merely extensions that aid the compiler in aiding > you. __attribute__((sentinel)) is squarely in this camp - compilers > that understand it can warn on questionable code, while you can > #define a wrapper to an empty string for all other compilers with no > change in program behavior. > > But __attribute__((cleanup)) is a special beast - it affects runtime > behavior, and if you use it, you are REQUIRED to have compiler > support. There is no way to write preprocessor macros that will > provide the same runtime functionality that cleanup implies for use by > a purely standards-compliant cc. That said, it is still a localized > compile-time effect, and does not impact ABI - it is merely reducing > (a lot!) of boilerplate coding that would otherwise be needed without > the attribute in play. I see no problem in mixing an executable that > uses it with a library that does not (nbdkit does just that - our > server uses cleanup, but can run a plugin compiled without cleanups > just fine), nor with mixing a library that uses it with an executable > does not (which could be the case if libnbd starts using it). > > Rather, the drawback of using __attribute__((cleanup)) in libnbd is > that we would now REQUIRE libnbd to be compiled with gcc or clang. > Right now, I don't know if anyone is trying to use libnbd with an > alternative compiler (no one has submitted patches or bug reports for > using libnbd under MSVC, for example), so it may be a non-issue. But > it's a one-way bridge - once we explicitly decide that we expect a > particular extension to the standards to even be able to use the > library, it becomes a lot harder to port the code to other platforms > without that specific compiler extension without replacing it back to > a lot of boilerplate code in its place. > > At the time we copied the vector code from nbdkit over to libnbd, we > weren't sure what environments would try to use libnbd, so we > intentionally did not port attribute cleanup stuff to avoid crippling > an unknown user. I'm not opposed to using the cleanup attribute, and > if we DO decide to use it, I'd love to go all in and utilize it > wherever it makes sense, which is more than just with of vectors. > Maybe the thing to do is have one major release where we announce our > intention to utilize the attribute in a future release, unless someone > speaks up with a reason why it would break with their preferred > toolchain; it delays the decision, and means we can't use it right > away, but at least would be a documented transition rather than a > blind "sorry you can't build anymore". > >> So those comments (esp. the one on commit f306e231d294) at least confirm >> that the difference is intentional. I still don't know the reason for >> the difference. And now I wonder: does the same (unexplained) reason >> underlie the "sentinel" attribute's absence too, in libnbd? >> >> If there is a common reason for avoiding both "cleanup" and "sentinel" >> in libnbd, we should probably not start using "sentinel" now. If, on the >> other hand, "sentinel" is not covered by the same argument as "cleanup" >> (not to mention if there isn't an actual reason for avoiding "cleanup" >> in the first place!), then I can add the sentinel attribute when merging >> this patch. > > I think the argument for not backporting "cleanup" is much different > than the one for not having needed to use "sentinel" to date.
Thanks for the detailed explanation. While I don't like this extra (orthogonal) complexity, I've made an effort to collect some information. (1) I couldn't figure out at what clang / gcc version the sentinel attribute was introduced. (2) The gcc manual says that __attribute__ ((__sentinel__)) is equivalent to __attribute__ ((sentinel)); it's just that the former is more suitable for public header files, to be included by client apps, where "sentinel" could already exist as a macro, while __sentinel__ couldn't. This is in fact (at least superficially) consistent with nbdkit's usage of the attribute; we have "__sentinel__" in "common/utils/utils.h" and "tests/test.h" (header files -- albeit not public), and "sentinel" in "tests/test-layers.c". So I'll squash "__attribute__ ((sentinel))" into the C code of this patch. (3) Whether or not we should add a wrapper macro. Libnbd is not really consistent in this regard. The generator defines LIBNBD_ATTRIBUTE_NONNULL and LIBNBD_ATTRIBUTE_ALLOC_DEALLOC -- those are for the public "libnbd.h" header, so the wrapper macros are certainly justified there. The question is however what the libnbd-internal code does. And that's *seemingly* inconsistent: (3.a) the internal code consumes LIBNBD_ATTRIBUTE_NONNULL and LIBNBD_ATTRIBUTE_ALLOC_DEALLOC liberally, from the public (generated) library header -- likely because that's the convenient thing to do, (3.b) in a single case, we have an internal-only wrapper: NBD_ATTRIBUTE_PACKED in "lib/nbd-protocol.h" (whose definition effectively enforces clang or gcc) -- and this seems to be shared with nbdkit, (3.c) we have a bunch of internal code that uses naked attributes, such as "__nonnull__", "__unused__", "constructor", "noreturn", "destructor", "packed". For (3.a) and (3.b), I can cook up a guiding principle -- both "libnbd.h" and "nbd-protocol.h" look public, at least to an extent, while the stuff in (3.c) is totally internal. So, I can equate wrapper macros to public headers, for now, and I won't introduce a new macro just for this one application of "__attribute__ ((sentinel))" in "lib/utils.c". Laszlo _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://listman.redhat.com/mailman/listinfo/libguestfs