Opened 10 years ago
Last modified 9 years ago
#7028 reopened Feature Requests
NDEBUG should disable asserts even if BOOST_ENABLE_ASSERT_HANDLER is defined
Reported by: | Mathias Gaunard | Owned by: | Peter Dimov |
---|---|---|---|
Milestone: | To Be Determined | Component: | utility |
Version: | Boost Development Trunk | Severity: | Problem |
Keywords: | BOOST_ASSERT assert BOOST_ENABLE_ASSERT_HANDLER NDEBUG | Cc: | k_satoda@… |
Description
I have some components that require the use of a specific assert handler.
Compiling those components in debug or release is something that should be fairly independent from the flags required to use my components.
Therefore it would be more practical for me if when both BOOST_ENABLE_ASSERT_HANDLER and NDEBUG are defined the assert handler is not called.
Attachments (1)
Change History (23)
comment:1 by , 10 years ago
comment:2 by , 10 years ago
Cc: | added |
---|
+1 for "when both BOOST_ENABLE_ASSERT_HANDLER and NDEBUG are defined the assert handler is not called".
Otherwise, a build configuration with BOOST_ENABLE_ASSERT_HANDLER needs additional control for BOOST_DISABLE_ASSERTS (unset for debug and set for release), which seems unreasonable because NDEBUG is already set (or unset) to take the same effect.
comment:3 by , 10 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
follow-up: 5 comment:4 by , 10 years ago
I'm opposed to the suggested resolution, until I hear a better reason. If you don't want your assert handler invoked in release builds, then don't define BOOST_ENABLE_ASSERT_HANDLER
. Simple.
As the code is now, it is possible to turn BOOST_ASSERT
into something like an ENSURE
macro that leaves the checks in, even for release builds. This is important in safety-critical applications -- exactly the same applications where a custom assert handler makes the most sense.
comment:5 by , 10 years ago
Replying to eric_niebler:
I'm opposed to the suggested resolution, until I hear a better reason. If you don't want your assert handler invoked in release builds, then don't define
BOOST_ENABLE_ASSERT_HANDLER
. Simple.As the code is now, it is possible to turn
BOOST_ASSERT
into something like anENSURE
macro that leaves the checks in, even for release builds. This is important in safety-critical applications -- exactly the same applications where a custom assert handler makes the most sense.
What prevents the users to use the test directly in their code. What am I missing?
comment:6 by , 10 years ago
Sorry, I have missed the history of this library. IUUC now the introduction of BOOST_ASSERT_MSG in [68414] introduce the defined(NDEBUG)
#if defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG) #define BOOST_ASSERT_MSG(expr, msg) ((void)0)
which made BOOST_ASSERT_MSG to behave differently than BOOST_ASSERT.
The introduction of BOOST_VERIFY using
#if defined(BOOST_DISABLE_ASSERTS) || ( !defined(BOOST_ENABLE_ASSERT_HANDLER) && defined(NDEBUG) )
made also a difference.
So should we remove the use of defined(NDEBUG) and update the documentation of BOOST_ASSERT_MSG?
follow-up: 9 comment:7 by , 10 years ago
I'd rather BOOST_ASSERT be modified to behave like BOOST_ASSERT_MSG does. I see to no reason to have to depend on a BOOST_DISABLE_ASSERTS macro when NDEBUG exists precisely for that purpose.
comment:8 by , 10 years ago
NDEBUG
does what it is supposed to, except when BOOST_ENABLE_ASSERT_HANDLER
is defined. That's how it's supposed to work. If you are building with NDEBUG
defined and you want assertions removed, then don't define BOOST_ENABLE_ASSERT_HANDLER
. Why would you, anyway?
comment:9 by , 10 years ago
Type: | Bugs → Feature Requests |
---|
Replying to mgaunard:
I'd rather BOOST_ASSERT be modified to behave like BOOST_ASSERT_MSG does. I see to no reason to have to depend on a BOOST_DISABLE_ASSERTS macro when NDEBUG exists precisely for that purpose.
I don't know what will be the outcome of this issue, but BOOST_ASSERT implementation corresponds to the documentation, so I think that this must be handled as a feature request.
comment:10 by , 10 years ago
Owner: | changed from | to
---|---|
Status: | assigned → new |
comment:11 by , 10 years ago
BOOST_ENABLE_ASSERT_HANDLER is a global flag (if asserts occur, I need to handle them in a specific way), while disabling assertions is a flag dependent on the build type. Both are orthogonal things.
comment:12 by , 10 years ago
Mathias, can you explain why you would define BOOST_ENABLE_ASSERT_HANDLER
when you don't want assertions?
comment:13 by , 10 years ago
If assertions occur, I need to print them or log them in a specific way. There is independent from whether assertions are enabled or not and is handled by different parts of my build system
follow-up: 15 comment:14 by , 10 years ago
IMO, "Because it makes my particular build setup simpler," isn't reason to change a long-standing and well-documented behavior. But I'll leave that for Peter to decide and quit this discussion.
Regardless, BOOST_ASSERT
and BOOST_ASSERT_MSG
must be made consistent.
comment:15 by , 10 years ago
Replying to eric_niebler:
Regardless,
BOOST_ASSERT
andBOOST_ASSERT_MSG
must be made consistent.
I agree, but...
The only way to make it completely consistent is for BOOST_ASSERT_MSG to be implemented in terms of assert.
#define NDEBUG #include <boost/assert.hpp> #undef NDEBUG #include <cassert>
(I actually favor implementing BOOST_ASSERT_MSG using assert anyway, as I rather dislike the fact that boost/assert.hpp #includes <iostream>)
comment:16 by , 10 years ago
Interesting point Steven. What do you have in mind? The classic assert( expr && "message" )?
Regarding the main point: the original purpose of BOOST_ASSERT was to be exactly equivalent to assert unless overridden by one of the other macros. So, when nothing is defined, it maps to assert, and hence honors NDEBUG. When BOOST_DISABLE_ASSERTS is defined, this is taken as a request to disable BOOST_ASSERT, even when the ordinary asserts are active; and when BOOST_ENABLE_ASSERT_HANDLER is defined, for consistency, this is taken as a request "route all BOOST_ASSERT macros to this handler, even when the ordinary asserts are inactive".
I can certainly see that in some use cases it is more convenient to make it do nothing in NDEBUG configurations even when BOOST_ENABLE_ASSERT_HANDLER is defined. Specifically, when BOOST_ASSERT is used as a library on its own. Its original purpose, however, was to provide a way for Boost libraries to use assertions in a way that can be controlled and overridden by the end user. Hence the current behavior.
comment:17 by , 9 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
comment:18 by , 9 years ago
Resolution: | wontfix |
---|---|
Status: | closed → reopened |
comment:19 by , 9 years ago
I've added support for the new macro BOOST_ENABLE_ASSERT_DEBUG_HANDLER, which works as requested. It disables assertions when NDEBUG is defined, and is equivalent to BOOST_ENABLE_ASSERT_HANDLER otherwise.
https://github.com/boostorg/assert/commit/f0e5bd15fb70c07ec943d01dc99aa4e507ceffe5
This commit also redefines BOOST_ASSERT_MSG(expr,msg) as assert((expr)&&(msg)) by default, for consistency with BOOST_ASSERT. I'm open to suggestions as to how to optionally provide the old behavior of BOOST_ASSERT_MSG, suitably extended to BOOST_ASSERT as well.
comment:21 by , 9 years ago
Replying to chris.cooper@…:
I think assert_test.cpp needs changed too?
Sorry, assert_test.cpp compiles just fine. I'm just confused on your intended usage ... in the patched version, line 59 looks like this:
( defined(BOOST_ENABLE_ASSERT_DEBUG_HANDLER) && defined(NDEBUG) ) |
so if I'm creating a release build (NDEBUG is defined) and I haven't defined BOOST_DISABLE_ASSERTS, then by defining BOOST_ENABLE_ASSERT_DEBUG_HANDLER, it disables BOOST_ASSERT_MSG (by #defining it to (void)0). So by defining a macro whose name contains ENABLE, I am disabling the ASSERT functionality?
comment:22 by , 9 years ago
In NDEBUG builds, when nothing else is defined, BOOST_ASSERT_MSG(expr, msg) is defined as assert((expr)&&(msg)), which is also the equivalent of ((void)0). So defining BOOST_ENABLE_ASSERT_DEBUG_HANDLER doesn't disable it any further.
Defining BOOST_DISABLE_ASSERTS instead of NDEBUG works. It would be good if both worked the same.
It also appears that BOOST_ASSERT has the problem but not BOOST_ASSERT_MSG.