Hi Jonathan,
Thanks for the suggestion, it seems promising. I switched out the
error attribute for the warning attribute at first, since they should
be equivalent except warning just warns instead of erroring. This
results in the link step failing if LTO is enabled for some reason
though. I then changed it to deprecated instead of warning, since
that's available on all compilers we support, but that breaks on clang
and VC because they seem to not do so well with redeclaring standard
library functions. I only have one card left up my sleeve, and that's
to use decltype:
[[deprecated("use os::malloc")]] decltype(::malloc) malloc;
Does ISO C++ allow you to redeclare something from the standard
library like this? Or is it still subject to the same ambiguity about
whether redeclaring C functions in the global namespace is allowed or
not that you mentioned before?
Thanks for the help!
best regards,
Julian
On Mon, Apr 14, 2025 at 7:57 PM Jonathan Wakely wrote:
>
> On Mon, 14 Apr 2025 at 11:53, Julian Waters wrote:
> >
> > Hi Jonathan,
> >
> > Yep, unfortunately #pragma GCC poison is far too restrictive, it
> > doesn't check if it is a function call to that particular banned
> > function, it restricts any and all use of that identifier in the code
> > altogether. Not only does this mean you can't use overloads of a
> > banned function, you can't use that identifier whatsoever, not even in
> > naming your own function. This presents some trouble, for example this
> > codebase has the following snippets in it:
> >
> > void* outerp = os::malloc(total_sz, mtInternal);
> >
> > And the declaration and definitions for os::malloc as well:
> >
> > // General allocation (must be MT-safe)
> > static void* malloc (size_t size, MemTag mem_tag, const
> > NativeCallStack& stack);
> > static void* malloc (size_t size, MemTag mem_tag);
> >
> > This is not the standard library malloc of course, but had I put
> > #pragma GCC poison malloc into a general header, these areas would've
> > immediately been flagged and the compilation would've been terminated
> > in an error. It's also prohibitively difficult to unpoison an
> > identifier poisoned this way, making it unsuitable for use in this
> > codebase, unfortunately
>
> I think this works, but is ugly (and I wouldn't accept it as a
> workaround personally):
>
> #define OS_MALLOC(a, b) os::malloc((a), (b))
> #pragma GCC poison malloc
>
> Now you can use OS_MALLOC everywhere instead of os::malloc. That's
> horrible though, and all uses of os::malloc need to be changed.
>
> You could just add the error attribute to existing functions:
>
> extern "C" [[error("use os::malloc instead")]] void* malloc(size_t);
>
> This seems to do exactly what you want:
> del.cc:9:21: error: call to ‘malloc’ declared with attribute error:
> use os::malloc instead
>
> The C++ standard doesn't allow redeclaring anything in namespace std,
> but I think it's less clear about C functions in the global namespace.
> In any case, it might be morally questionable, but it works. And since
> what you want is to prevent the function being called, the usual
> concerns about redeclaring it don't really apply.
>
> You can probably come up with some macro-based solution to allow
> calling it in specific places, such as simply arranging for the
> redeclaration with gnu::error to not be visible where you need to use
> it.