Re: Compiler support for forbidding certain methods from being called

2025-04-14 Thread Jonathan Wakely via Gcc
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

2025-04-14 Thread Jonathan Wakely via Gcc
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

2025-04-14 Thread Jonathan Wakely via Gcc
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

2025-04-14 Thread Basile Starynkevitch
> 
> 
> 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

2025-04-14 Thread Jonathan Wakely via Gcc
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

2025-04-14 Thread Julian Waters via Gcc
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

2025-04-14 Thread Julian Waters via Gcc
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

2025-04-14 Thread justin.colon--- via Gcc
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

2025-04-14 Thread Mark Wielaard
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