Hi Everyone, On Fri, May 30, 2025 Lino Mastrodomenico <l.mastrodomen...@gmail.com> wrote: > > > On May 29, 2025, Lino Mastrodomenico <l.mastrodomen...@gmail.com> wrote: > > > Because what gcc does is "required semantics"? Maybe it is just undefined > > behavior, like in > > int n=0,*p=&n; return n + (*p=1); > > I can't find a detailed specification for cleanup, so this might have > been initially undefined behavior or an implementation detail. > > But Hyrum's Law (https://www.hyrumslaw.com/ ) requires that any such > undefined behavior becomes required semantics if it's implemented > consistently, and indeed it's common for glib/GTK code to assume that > the cleanup has not happened yet while the return expression is being > evaluated (in glib, g_auto is a wrapper around > __attribute__((cleanup))). See e.g. the code in this example, which > relies on this detail: > https://docs.gtk.org/glib/auto-cleanup.html#variable-declaration
I would like to state, for the record, that it is not a matter of implementation-defined or undefined behavior that cleanup -- or any of its derivative or similarly-designed counterparts in other languages -- it is a matter of predictable, well-defined behavior that can interop in a normal way with other parts of the language. Here's some basic code illustrating an oft-used idiom: #include <stdio.h> #include <stdlib.h> void f(void* arg) { free(*((void**)arg)); } int use_buffer(void* buf) { (void)buf; // just example code return 0xFF; } int test () { __attribute__((cleanup(f))) void* buffer = malloc(30); return use_buffer(buffer); } int main () { return test(); } (https://godbolt.org/z/zhsn4fa5K) Calling the cleanup function `f` before calling use_buffer is a one-way ticket to a use-after-free. This is relatively simple code to illustrate a point, but code that behaves in this same functional manner with the existing attribute is very prominent, as Limo pointed out. People are not depending on this property by accident. "Run the cleanup code when technically the declarations -- buffers, files, etc. -- are still reachable and usable" is not a good design. Limo's other examples point this out, as does the feature that will one day hope to put a formalization of this feature into C. Every other language that has a cleanup attribute-style feature (C++ destructors, C# Dispose, python using-with, Rust Drop) behaves in exactly the same way (https://godbolt.org/z/KzYnj4rq7 | https://godbolt.org/z/rvh6cWa1E | https://godbolt.org/z/aqq6GfG6r | https://godbolt.org/z/zjzMnT845). While I understand the temptation to chalk up GCC or Clang's lack of documentation of this fact that it could be undefined, implementation-defined, or somehow optional behavior, I would strongly, deeply push back on the idea that it is. I think it's an important fundamental property of any iteration of such a feature, and I think it would be good if it was upheld properly, both for the strong existing practice across all of its iterations and implementations as well as the clear and present dangers that come with invoking before return expressions are evaluated. Thanks for reading, JeanHeyd _______________________________________________ Tinycc-devel mailing list Tinycc-devel@nongnu.org https://lists.nongnu.org/mailman/listinfo/tinycc-devel