Date: Thu, 23 Oct 2025 15:16:10 -0700
Tom:
> Why do you want to use contracts to provide that guarantee?
>
> From my perspective, an unconditional-always-enforce contract semantic
> changes a function that has a narrow contract into a function that has a
> wide contract (or at least a wider contract subject to contracts that are
> actually expressible in the language). Contracts aren't needed to do that;
> we can express wider contracts in code today.
Because run-time validation is not for program bugs. Just as assertions are not for run-time input validation.
A canonical example is a bounds check precondition:
pre( 0 <= idx && idx < vec.size() )
First, when should this be a contract vs. a widened precondition?
* If the subscript could be out of bounds because it’s run-time input (say), then yes I should instead widen the function contract and handle it. Assertions are not for run-time input validation.
* But if the subscript is calculated by the program, then I should NOT widen the contract because any violation really is a program bug. Run-time validation is not for program bugs.
Second, if it’s a bug and so we’re using a contract, when should it be enforced in production?
* A violation of a memory safety precondition, such as out-of-bounds access, is a violation of the abstract machine, same as stack overflow; it means the program itself is not a valid program(!). This is an essential distinction, and the category of bugs that are often exploitable vulnerabilities. (As opposed to business logic violations which might also be serious and we might or might not want to fail-fast on, but are different because they’re not in the “the program itself is not a valid program” territory.)
* And “if” we additionally are compiling security-critical code, we may have a requirement that we must check and fail-fast for memory safety violations (but not necessarily others, such as calculating the wrong average temperature in a weather app).
Summarizing: If idx is computed by the program, and we’re in security-critical code (such as we want a guaranteed-hardened standard library), we want this to be an assertion that is enforced in production. It’s true that we can’t yet express that in C++26 contracts, and that the labels extension would let us express it (among other things).
Does that example help?
BTW this is the first thing I discussed in my CppCon contracts talk starting at 19:39 <https://youtu.be/oitYvDe4nps?si=7hhanvoZOiH8WRuE&t=1179> as a prelude to giving usage guidance suggestions, because it’s an important distinction. Good question!
From: SG21 <sg21-bounces_at_[hidden]> On Behalf Of Tom Honermann via SG21
Sent: Thursday, October 23, 2025 9:21 AM
To: sg21_at_[hidden]; Gašper Ažman <gasper.azman_at_[hidden]>
Cc: Tom Honermann <tom_at_[hidden]>; Harald Achitz <harald_at_[hidden]>; sg15_at_[hidden]
Subject: Re: [isocpp-sg21] [isocpp-sg15] P3835 -- Different contract checking for different libraries
On 10/22/25 10:26 AM, John Spicer via SG21 wrote:
That still fails to do what i want, which is to have the library provide know that the semantic they choose will be the one used when the program is linked.
The following question is, again, intended as a serious one.
Why do you want to use contracts to provide that guarantee?
>From my perspective, an unconditional-always-enforce contract semantic changes a function that has a narrow contract into a function that has a wide contract (or at least a wider contract subject to contracts that are actually expressible in the language). Contracts aren't needed to do that; we can express wider contracts in code today. Is the desire based on wanting integration with a contract violation handler? Or a desire to express hardened preconditions in the function interface so that they are available for static analysis or caller-side optimization?
Assuming those capture your motivation, how far would support for a syntax like the following go towards satisfying your desire?
int* find(int *begin, int *end, int item)
pre hardened (begin != nullptr) // Hardened preconditions;
pre hardened (end != nullptr) // always evaluated with a
pre hardened (begin <= end) // terminating contract semantic.
pre (is_sorted(begin, end) // Not a hardened precondition.
;
It also sounds like this is mostly a variant of runtime semantic selection, which requires the code for all possible semantic varients to be emitted, which is a non-starter for most production code.
For what it is worth, I agree that is a non-starter for most production code with the linkers and loaders in use today.
This is a bit of a tangent, but my expectation, based on post link optimization work I'm aware of but can't talk about, is that future linkers and loaders will be able to support optimizing at load-time based on a load-time selected contract semantic (similar to JIT enablement of Java assertions by JVMs). I can't promise that such technologies will ever be deployed of course or on any meaningful timeline. I want to ensure the C++ standard does not prohibit use of such future optimization possibilities by requiring a compile-time selected semantic by default (I'm ok with an explicit opt-in as in the example above).
Tom.
John.
On Oct 20, 2025, at 7:33 AM, Gašper Ažman <mailto:gasper.azman_at_[hidden]> <gasper.azman_at_[hidden]> wrote:
You can definitely do it with conventional linkers. You guard the check with a link-time constant semantic at code emission; you let the linker fill those in. The link-time constant is a global that the linker deduplicates.
You can also introduce additional labels that skip the checks in the preconditions, and let the linker resolve the calls to those. Normal linkers do this. It works for weak symbols too.
On Mon, Oct 20, 2025 at 11:57 AM John Spicer <jhspicer_at_[hidden] <mailto:jhspicer_at_[hidden]> > wrote:
That assumes facilities that linkers might not have, and even if they have them, it may require expert use to select the version of the function you want.
This also potentially requires you to *know* which functions you and your libraries use.
On most systems with conventional linkers you do not have the capability you describe.
John.
On Oct 20, 2025, at 6:52 AM, Gašper Ažman via SG21 <sg21_at_[hidden] <mailto:sg21_at_[hidden]> > wrote:
John,
it shouldn't be "assigned randomly" - it's at best a final link-time property (as specified). The final link (+LTO) can do it.
On Mon, Oct 20, 2025 at 11:50 AM John Spicer <jhspicer_at_[hidden] <mailto:jhspicer_at_[hidden]> > wrote:
The problem is that for function templates, member functions of class templates, and inline functions, the semantic is essentially assigned randomly if it is used in multiple TUs that are compiled with different semantics.
In most complex environments you are dealing with things like libraries that are provided by others, so you may not have control over how it is built.
You can also have two libraries that use a third library, but if those two libraries are a different semantic any user of the third library has no idea what semantic they’ll get even if their code also uses the third library and is built with a particular semantic.
John.
On Oct 17, 2025, at 11:45 AM, Gašper Ažman via SG21 <sg21_at_[hidden] <mailto:sg21_at_[hidden]> > wrote:
+1 to what Tom said.
One part of this discussion is speaking as if semantics are assigned randomly or arbitrarily, where they are assigned by the person who ships the product - it has been pointed out time and time again that the actor deploying the application is the final arbiter of what "safe" means for a given contract check, because it's actually a function of "safe(context) -> bloom" (where "bloom" is a type with exactly two values of "no" and "perhaps").
The stakeholder with the best context is the deployer of the application; the farther away you go from that stakeholder, the less context they have. Deferring the choice of semantic to as late as possible gives a better outcome.
On Fri, Oct 17, 2025 at 4:33 PM Tom Honermann via SG21 <sg21_at_[hidden] <mailto:sg21_at_[hidden]> > wrote:
On Oct 17, 2025, at 10:23 AM, Harald Achitz via SG21 <sg21_at_[hidden] <mailto:sg21_at_[hidden]> > wrote:
On 2025-10-17 16:00, René Ferdinand Rivera Morell wrote:
On Fri, Oct 17, 2025 at 8:53 AM Harald Achitz via SG15 <sg15_at_[hidden] <mailto:sg15_at_[hidden]> > wrote:
Today's
void fun(Foo* ptr) {
my_supper_assert_macro (ptr!=nullpter);
my_supper_assert_macro(ptr->hasData());
}
should not have any problems, ever
AFAIU, if my_supper_assert_macro implements something equivalent to observe, that is still UB at present. Or is it EB now?
> Why do you want to use contracts to provide that guarantee?
>
> From my perspective, an unconditional-always-enforce contract semantic
> changes a function that has a narrow contract into a function that has a
> wide contract (or at least a wider contract subject to contracts that are
> actually expressible in the language). Contracts aren't needed to do that;
> we can express wider contracts in code today.
Because run-time validation is not for program bugs. Just as assertions are not for run-time input validation.
A canonical example is a bounds check precondition:
pre( 0 <= idx && idx < vec.size() )
First, when should this be a contract vs. a widened precondition?
* If the subscript could be out of bounds because it’s run-time input (say), then yes I should instead widen the function contract and handle it. Assertions are not for run-time input validation.
* But if the subscript is calculated by the program, then I should NOT widen the contract because any violation really is a program bug. Run-time validation is not for program bugs.
Second, if it’s a bug and so we’re using a contract, when should it be enforced in production?
* A violation of a memory safety precondition, such as out-of-bounds access, is a violation of the abstract machine, same as stack overflow; it means the program itself is not a valid program(!). This is an essential distinction, and the category of bugs that are often exploitable vulnerabilities. (As opposed to business logic violations which might also be serious and we might or might not want to fail-fast on, but are different because they’re not in the “the program itself is not a valid program” territory.)
* And “if” we additionally are compiling security-critical code, we may have a requirement that we must check and fail-fast for memory safety violations (but not necessarily others, such as calculating the wrong average temperature in a weather app).
Summarizing: If idx is computed by the program, and we’re in security-critical code (such as we want a guaranteed-hardened standard library), we want this to be an assertion that is enforced in production. It’s true that we can’t yet express that in C++26 contracts, and that the labels extension would let us express it (among other things).
Does that example help?
BTW this is the first thing I discussed in my CppCon contracts talk starting at 19:39 <https://youtu.be/oitYvDe4nps?si=7hhanvoZOiH8WRuE&t=1179> as a prelude to giving usage guidance suggestions, because it’s an important distinction. Good question!
From: SG21 <sg21-bounces_at_[hidden]> On Behalf Of Tom Honermann via SG21
Sent: Thursday, October 23, 2025 9:21 AM
To: sg21_at_[hidden]; Gašper Ažman <gasper.azman_at_[hidden]>
Cc: Tom Honermann <tom_at_[hidden]>; Harald Achitz <harald_at_[hidden]>; sg15_at_[hidden]
Subject: Re: [isocpp-sg21] [isocpp-sg15] P3835 -- Different contract checking for different libraries
On 10/22/25 10:26 AM, John Spicer via SG21 wrote:
That still fails to do what i want, which is to have the library provide know that the semantic they choose will be the one used when the program is linked.
The following question is, again, intended as a serious one.
Why do you want to use contracts to provide that guarantee?
>From my perspective, an unconditional-always-enforce contract semantic changes a function that has a narrow contract into a function that has a wide contract (or at least a wider contract subject to contracts that are actually expressible in the language). Contracts aren't needed to do that; we can express wider contracts in code today. Is the desire based on wanting integration with a contract violation handler? Or a desire to express hardened preconditions in the function interface so that they are available for static analysis or caller-side optimization?
Assuming those capture your motivation, how far would support for a syntax like the following go towards satisfying your desire?
int* find(int *begin, int *end, int item)
pre hardened (begin != nullptr) // Hardened preconditions;
pre hardened (end != nullptr) // always evaluated with a
pre hardened (begin <= end) // terminating contract semantic.
pre (is_sorted(begin, end) // Not a hardened precondition.
;
It also sounds like this is mostly a variant of runtime semantic selection, which requires the code for all possible semantic varients to be emitted, which is a non-starter for most production code.
For what it is worth, I agree that is a non-starter for most production code with the linkers and loaders in use today.
This is a bit of a tangent, but my expectation, based on post link optimization work I'm aware of but can't talk about, is that future linkers and loaders will be able to support optimizing at load-time based on a load-time selected contract semantic (similar to JIT enablement of Java assertions by JVMs). I can't promise that such technologies will ever be deployed of course or on any meaningful timeline. I want to ensure the C++ standard does not prohibit use of such future optimization possibilities by requiring a compile-time selected semantic by default (I'm ok with an explicit opt-in as in the example above).
Tom.
John.
On Oct 20, 2025, at 7:33 AM, Gašper Ažman <mailto:gasper.azman_at_[hidden]> <gasper.azman_at_[hidden]> wrote:
You can definitely do it with conventional linkers. You guard the check with a link-time constant semantic at code emission; you let the linker fill those in. The link-time constant is a global that the linker deduplicates.
You can also introduce additional labels that skip the checks in the preconditions, and let the linker resolve the calls to those. Normal linkers do this. It works for weak symbols too.
On Mon, Oct 20, 2025 at 11:57 AM John Spicer <jhspicer_at_[hidden] <mailto:jhspicer_at_[hidden]> > wrote:
That assumes facilities that linkers might not have, and even if they have them, it may require expert use to select the version of the function you want.
This also potentially requires you to *know* which functions you and your libraries use.
On most systems with conventional linkers you do not have the capability you describe.
John.
On Oct 20, 2025, at 6:52 AM, Gašper Ažman via SG21 <sg21_at_[hidden] <mailto:sg21_at_[hidden]> > wrote:
John,
it shouldn't be "assigned randomly" - it's at best a final link-time property (as specified). The final link (+LTO) can do it.
On Mon, Oct 20, 2025 at 11:50 AM John Spicer <jhspicer_at_[hidden] <mailto:jhspicer_at_[hidden]> > wrote:
The problem is that for function templates, member functions of class templates, and inline functions, the semantic is essentially assigned randomly if it is used in multiple TUs that are compiled with different semantics.
In most complex environments you are dealing with things like libraries that are provided by others, so you may not have control over how it is built.
You can also have two libraries that use a third library, but if those two libraries are a different semantic any user of the third library has no idea what semantic they’ll get even if their code also uses the third library and is built with a particular semantic.
John.
On Oct 17, 2025, at 11:45 AM, Gašper Ažman via SG21 <sg21_at_[hidden] <mailto:sg21_at_[hidden]> > wrote:
+1 to what Tom said.
One part of this discussion is speaking as if semantics are assigned randomly or arbitrarily, where they are assigned by the person who ships the product - it has been pointed out time and time again that the actor deploying the application is the final arbiter of what "safe" means for a given contract check, because it's actually a function of "safe(context) -> bloom" (where "bloom" is a type with exactly two values of "no" and "perhaps").
The stakeholder with the best context is the deployer of the application; the farther away you go from that stakeholder, the less context they have. Deferring the choice of semantic to as late as possible gives a better outcome.
On Fri, Oct 17, 2025 at 4:33 PM Tom Honermann via SG21 <sg21_at_[hidden] <mailto:sg21_at_[hidden]> > wrote:
On Oct 17, 2025, at 10:23 AM, Harald Achitz via SG21 <sg21_at_[hidden] <mailto:sg21_at_[hidden]> > wrote:
On 2025-10-17 16:00, René Ferdinand Rivera Morell wrote:
On Fri, Oct 17, 2025 at 8:53 AM Harald Achitz via SG15 <sg15_at_[hidden] <mailto:sg15_at_[hidden]> > wrote:
Today's
void fun(Foo* ptr) {
my_supper_assert_macro (ptr!=nullpter);
my_supper_assert_macro(ptr->hasData());
}
should not have any problems, ever
AFAIU, if my_supper_assert_macro implements something equivalent to observe, that is still UB at present. Or is it EB now?
-- -- René Ferdinand Rivera Morell -- Don't Assume Anything -- No Supongas Nada -- Robot Dreams - http://robot-dreams.net <http://robot-dreams.net/> On devices that keep you alive, one example where I have seen such super asserts in action, contracts are contracts They do not exist only sometimes. Correct, (plain language) contracts are omnipresent. The contract checking statements above violate the function contract and are thus defective. Static analysis can diagnose such cases. For example, I would expect a contracts enabled version of Coverity to report a FORWARD_NULL issue for the above code. I am not even sure if contracts as specified would pass regulatory requirements, I think not. I’m not an expert on the subject by any means, but I would expect regulatory requirements to consider the manner in which the software is built; just as they consider the content of the source code and require other supply chain guards. A requirement that deployed software not contain portions for which the observe semantic is selected seems reasonable and prudent. Tom. /Harald _______________________________________________ SG21 mailing list SG21_at_[hidden] <mailto:SG21_at_[hidden]> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21 Link to this post: http://lists.isocpp.org/sg21/2025/10/11351.php _______________________________________________ SG21 mailing list SG21_at_[hidden] <mailto:SG21_at_[hidden]> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21 Link to this post: http://lists.isocpp.org/sg21/2025/10/11352.php _______________________________________________ SG21 mailing list SG21_at_[hidden] <mailto:SG21_at_[hidden]> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21 Link to this post: <http://lists.isocpp.org/sg21/2025/10/11422.php> http://lists.isocpp.org/sg21/2025/10/11422.php _______________________________________________ SG21 mailing list SG21_at_[hidden] <mailto:SG21_at_[hidden]> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21 Link to this post: http://lists.isocpp.org/sg21/2025/10/11687.php
Received on 2025-10-23 22:16:15
