Re: Compiler support for forbidding certain methods from being called
On Mon, 14 Apr 2025 at 14:47, Julian Waters wrote: > > 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? I don't think that changes anything. The C++ standard explicitly forbids adding declarations to namespace std: "Unless otherwise specified, the behavior of a C ++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std." But ::malloc is not in namespace std, so that rule doesn't apply. But that's arguably a defect in the standard caused by forgetting that std::malloc might actually be defined as ::malloc. Re-declaring ::malloc is probably against the spirit of the rule, even if not strictly breaking it.
Re: Compiler support for forbidding certain methods from being called
On Mon, 14 Apr 2025 at 10:11, Julian Waters via Gcc wrote: > > Hi all, > > A codebase I'm working with has decided that poisoning certain > standard library functions is necessary, as it explicitly does not use > those functions unless absolutely necessary for its own reasons (This > was not my decision to make). As such, we've been looking into ways to > implement that. > > The problem is there's really no way at all to forbid standard library > functions. The crucial thing is that this mechanism must have a > disable switch for when a callsite must actually call a forbidden > function, complicating the whole process. > > It would be nice to have compiler support to help with this. Something like: > > #pragma GCC forbidden void *malloc(size_t) // Forbids malloc from > being called anywhere Have you looked at https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html#index-_0023pragma-GCC-poison ? > #pragma GCC permitted push > #pragma GCC permitted void *malloc(size_t) > void *ptr = malloc(1); // This callsite must use malloc, bypassing the > usual restriction > #pragma GCC permitted pop > > However, I'm guessing this would be a bit complex to implement. There > are other ways I have tried as well, such as: > > #include > > namespace permitted { > using ::malloc; > } > > inline namespace forbidden { > [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; > } > > int main() { > void *ptr = malloc(1); // Should raise an error, must call > permitted::malloc(1) to avoid > free(ptr); > } > > The problem with the above is that the error isn't from the function > being deleted or marked as deprecated, it's an ambiguity error that is > confusing and doesn't tell the developer why the error is actually > happening (Because the function has been forbidden). Additionally, > there is no way to disable this system in third party headers included > from the testing framework, making it unusable. Given this, could I > request some sort of compiler specific "shadow" attribute that can be > applied to a namespace? With this attribute, the symbols in this > namespace will take precedence over the symbols of the namespace it is > in (Including the global namespace, if its parent is in the global > namespace) if it is injected into the parent, either because it is > inline, unnamed, or because of a using namespace x; declaration. This > contrasts with the standard behaviour of raising an ambiguity error > when trying to resolve which symbol to use, instead, the symbol from > the namespace marked as shadow will always be given precedence. > > #include > > namespace permitted { > using ::malloc; > } > > inline namespace [[gnu::shadow]] forbidden { > [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; > } > > int main() { > void *ptr = malloc(1); // Correct error shown, forbidden::malloc > chosen over standard library > free(ptr); > } > > Ideally shadow could have another effect on using declarations. > Normally, trying to do a using declaration to choose between 2 > conflicting symbols will just fail: > > #include > > namespace permitted { > using ::malloc; > } > > inline namespace forbidden { > [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; > } > > using forbidden::malloc; > > int main() { > void *ptr = malloc(1); > free(ptr); > } > > :11:18: error: 'void* forbidden::malloc(size_t)' conflicts > with a previous declaration > 11 | using forbidden::malloc; > | ^~ > > Perhaps, if one of those symbols comes from a namespace marked as > shadow, the using declaration would instead behave differently, > choosing which declaration is used instead of just bringing the > declaration into scope: > > #include > > namespace permitted { > using ::malloc; > } > > inline namespace [[gnu::shadow]] forbidden { > [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; > } > > using forbidden::malloc; // From now on, any calls to malloc use > forbidden::malloc > using ::malloc; // From now on, any call to malloc go to ::malloc > using permitted::malloc; // From now on, any call to malloc goes to > permitted::malloc > > Or alternatively, is there a better way to do this instead of adding > custom support to the compiler? The gcc static analyzer doesn't seem > to support C++ yet nor does it seem to have a configurable check for > whether you are calling a given function, neither does VC for that > matter. Maybe this could be an analyzer request instead of a compiler > feature request. Either way, I'm open to suggestions. > > best regards, > Julian
Re: Compiler support for forbidding certain methods from being called
On Mon, 14 Apr 2025 at 12:57, 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); Oops sorry, that should be gnu::error not error. > > 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.
Compiler support for forbidding certain methods from being called
> > > A codebase I'm working with has decided that poisoning certain > standard library functions is necessary, as it explicitly does not use > those functions unless absolutely necessary for its own reasons (This > was not my decision to make). As such, we've been looking into ways to > implement that. > > The problem is there's really no way at all to forbid standard library > functions. The crucial thing is that this mechanism must have a > disable switch for when a callsite must actually call a forbidden > function, complicating the whole process. > > It would be nice to have compiler support to help with this. I would recommend writing your GCC plugin which would add some problem specific pragmas. Some code from https://github.com/bstarynk/bismon might be improved (by you or your colleagues/interns) to fit into latest GCC version. See http://www.starynkevitch.net/Basile/bismon-chariot-doc.pdf and https://www.decoder-project.eu In some cases, https://frama-c.com/ could also be useful. Regards. -- Basile STARYNKEVITCH 8 rue de la Faïencerie http://starynkevitch.net/Basile/ 92340 Bourg-la-Reine https://github.com/bstarynk Francehttps://github.com/RefPerSys/RefPerSys
Re: Compiler support for forbidding certain methods from being called
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.
Re: Compiler support for forbidding certain methods from being called
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 best regards, Julian On Mon, Apr 14, 2025 at 6:32 PM Jonathan Wakely wrote: > > On Mon, 14 Apr 2025 at 10:11, Julian Waters via Gcc wrote: > > > > Hi all, > > > > A codebase I'm working with has decided that poisoning certain > > standard library functions is necessary, as it explicitly does not use > > those functions unless absolutely necessary for its own reasons (This > > was not my decision to make). As such, we've been looking into ways to > > implement that. > > > > The problem is there's really no way at all to forbid standard library > > functions. The crucial thing is that this mechanism must have a > > disable switch for when a callsite must actually call a forbidden > > function, complicating the whole process. > > > > It would be nice to have compiler support to help with this. Something like: > > > > #pragma GCC forbidden void *malloc(size_t) // Forbids malloc from > > being called anywhere > > Have you looked at > https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html#index-_0023pragma-GCC-poison > ? > > > > #pragma GCC permitted push > > #pragma GCC permitted void *malloc(size_t) > > void *ptr = malloc(1); // This callsite must use malloc, bypassing the > > usual restriction > > #pragma GCC permitted pop > > > > However, I'm guessing this would be a bit complex to implement. There > > are other ways I have tried as well, such as: > > > > #include > > > > namespace permitted { > > using ::malloc; > > } > > > > inline namespace forbidden { > > [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; > > } > > > > int main() { > > void *ptr = malloc(1); // Should raise an error, must call > > permitted::malloc(1) to avoid > > free(ptr); > > } > > > > The problem with the above is that the error isn't from the function > > being deleted or marked as deprecated, it's an ambiguity error that is > > confusing and doesn't tell the developer why the error is actually > > happening (Because the function has been forbidden). Additionally, > > there is no way to disable this system in third party headers included > > from the testing framework, making it unusable. Given this, could I > > request some sort of compiler specific "shadow" attribute that can be > > applied to a namespace? With this attribute, the symbols in this > > namespace will take precedence over the symbols of the namespace it is > > in (Including the global namespace, if its parent is in the global > > namespace) if it is injected into the parent, either because it is > > inline, unnamed, or because of a using namespace x; declaration. This > > contrasts with the standard behaviour of raising an ambiguity error > > when trying to resolve which symbol to use, instead, the symbol from > > the namespace marked as shadow will always be given precedence. > > > > #include > > > > namespace permitted { > > using ::malloc; > > } > > > > inline namespace [[gnu::shadow]] forbidden { > > [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; > > } > > > > int main() { > > void *ptr = malloc(1); // Correct error shown, forbidden::malloc > > chosen over standard library > > free(ptr); > > } > > > > Ideally shadow could have another effect on using declarations. > > Normally, trying to do a using declaration to choose between 2 > > conflicting symbols will just fail: > > > > #include > > > > namespace permitted { > > using ::malloc; > > } > > > > inline namespace forbidden { > > [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; > > } > > > > using forbidden::malloc; > > > > int main() { > > void *ptr = malloc(1); > > free(ptr); > > } > > > > :11:18: error: 'void* forbidden::malloc(size_t)' conflicts > > with a previous declaration > > 11 | using forbidden::malloc; > > | ^~ > > > > Perhaps, if one of those symbols comes from a namespace marked as > > shadow
Compiler support for forbidding certain methods from being called
Hi all, A codebase I'm working with has decided that poisoning certain standard library functions is necessary, as it explicitly does not use those functions unless absolutely necessary for its own reasons (This was not my decision to make). As such, we've been looking into ways to implement that. The problem is there's really no way at all to forbid standard library functions. The crucial thing is that this mechanism must have a disable switch for when a callsite must actually call a forbidden function, complicating the whole process. It would be nice to have compiler support to help with this. Something like: #pragma GCC forbidden void *malloc(size_t) // Forbids malloc from being called anywhere #pragma GCC permitted push #pragma GCC permitted void *malloc(size_t) void *ptr = malloc(1); // This callsite must use malloc, bypassing the usual restriction #pragma GCC permitted pop However, I'm guessing this would be a bit complex to implement. There are other ways I have tried as well, such as: #include namespace permitted { using ::malloc; } inline namespace forbidden { [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; } int main() { void *ptr = malloc(1); // Should raise an error, must call permitted::malloc(1) to avoid free(ptr); } The problem with the above is that the error isn't from the function being deleted or marked as deprecated, it's an ambiguity error that is confusing and doesn't tell the developer why the error is actually happening (Because the function has been forbidden). Additionally, there is no way to disable this system in third party headers included from the testing framework, making it unusable. Given this, could I request some sort of compiler specific "shadow" attribute that can be applied to a namespace? With this attribute, the symbols in this namespace will take precedence over the symbols of the namespace it is in (Including the global namespace, if its parent is in the global namespace) if it is injected into the parent, either because it is inline, unnamed, or because of a using namespace x; declaration. This contrasts with the standard behaviour of raising an ambiguity error when trying to resolve which symbol to use, instead, the symbol from the namespace marked as shadow will always be given precedence. #include namespace permitted { using ::malloc; } inline namespace [[gnu::shadow]] forbidden { [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; } int main() { void *ptr = malloc(1); // Correct error shown, forbidden::malloc chosen over standard library free(ptr); } Ideally shadow could have another effect on using declarations. Normally, trying to do a using declaration to choose between 2 conflicting symbols will just fail: #include namespace permitted { using ::malloc; } inline namespace forbidden { [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; } using forbidden::malloc; int main() { void *ptr = malloc(1); free(ptr); } :11:18: error: 'void* forbidden::malloc(size_t)' conflicts with a previous declaration 11 | using forbidden::malloc; | ^~ Perhaps, if one of those symbols comes from a namespace marked as shadow, the using declaration would instead behave differently, choosing which declaration is used instead of just bringing the declaration into scope: #include namespace permitted { using ::malloc; } inline namespace [[gnu::shadow]] forbidden { [[deprecated("use os::malloc")]] void *malloc(size_t) throw() = delete; } using forbidden::malloc; // From now on, any calls to malloc use forbidden::malloc using ::malloc; // From now on, any call to malloc go to ::malloc using permitted::malloc; // From now on, any call to malloc goes to permitted::malloc Or alternatively, is there a better way to do this instead of adding custom support to the compiler? The gcc static analyzer doesn't seem to support C++ yet nor does it seem to have a configurable check for whether you are calling a given function, neither does VC for that matter. Maybe this could be an analyzer request instead of a compiler feature request. Either way, I'm open to suggestions. best regards, Julian
Something Blocking Access from Lockheed Martin External IP Space to gcc.gnu.org
Hello GCC and GNU support, I am the proxy service lead for Lockheed Martin and something seems to be blocking our traffic when our US users try to reach https://gcc.gnu.org/onlinedocs/. Our Non-US users do not have the same issues. Our reserved Zscaler IP Space for US users is the following: 136.226.7.128/25 (San Jose) 136.226.98.128/25 (San Jose) 136.226.19.128/25 (Washington DC) 136.226.154.0/25 (Washington DC) Can you check if there is something on your end blocking traffic from these subnets? Thanks, Justin Colon Enterprise IT -- Corporate Information Security CELL (303) 815 5738
Re: Something Blocking Access from Lockheed Martin External IP Space to gcc.gnu.org
Hi, On Mon, Apr 14, 2025 at 09:51:50PM +, justin.colon--- via Gcc wrote: > Hello GCC and GNU support, I am the proxy service lead for Lockheed > Martin and something seems to be blocking our traffic when our US > users try to reach https://gcc.gnu.org/onlinedocs/. Our Non-US users > do not have the same issues. Our reserved Zscaler IP Space for US > users is the following: > > 136.226.7.128/25 (San Jose) > 136.226.98.128/25 (San Jose) > 136.226.19.128/25 (Washington DC) > 136.226.154.0/25 (Washington DC) > > Can you check if there is something on your end blocking traffic > from these subnets? Sorry we had blocked the whole 136.226.0.0/16 block from Zscaler because of bad traffic. We are currently fighting LLM/AI scraperbots hitting various sites very hard. https://lwn.net/Articles/1008897/ https://arstechnica.com/ai/2025/03/devs-say-ai-crawlers-dominate-traffic-forcing-blocks-on-entire-countries/ Cheers, Mark