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)

7028.patch (626 bytes ) - added by viboes 10 years ago.
Is this patch enough?

Download all attachments as: .zip

Change History (23)

comment:1 by Mathias Gaunard, 10 years ago

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.

comment:2 by Kazutoshi Satoda <k_satoda@…>, 10 years ago

Cc: k_satoda@… 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.

by viboes, 10 years ago

Attachment: 7028.patch added

Is this patch enough?

comment:3 by viboes, 10 years ago

Owner: changed from No-Maintainer to viboes
Status: newassigned

comment:4 by Eric Niebler, 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.

in reply to:  4 comment:5 by viboes, 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 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.

What prevents the users to use the test directly in their code. What am I missing?

Last edited 10 years ago by viboes (previous) (diff)

comment:6 by viboes, 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?

comment:7 by Mathias Gaunard, 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 Eric Niebler, 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?

in reply to:  7 comment:9 by viboes, 10 years ago

Type: BugsFeature 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 viboes, 10 years ago

Owner: changed from viboes to Peter Dimov
Status: assignednew

comment:11 by Mathias Gaunard, 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 Eric Niebler, 10 years ago

Mathias, can you explain why you would define BOOST_ENABLE_ASSERT_HANDLER when you don't want assertions?

comment:13 by Mathias Gaunard, 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

comment:14 by Eric Niebler, 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.

in reply to:  14 comment:15 by Steven Watanabe, 10 years ago

Replying to eric_niebler:

Regardless, BOOST_ASSERT and BOOST_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 Peter Dimov, 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 Peter Dimov, 9 years ago

Resolution: wontfix
Status: newclosed

comment:18 by Peter Dimov, 9 years ago

Resolution: wontfix
Status: closedreopened

comment:19 by Peter Dimov, 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:20 by chris.cooper@…, 9 years ago

I think assert_test.cpp needs changed too?

in reply to:  20 comment:21 by chris.cooper@…, 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:

#if defined(BOOST_DISABLE_ASSERTS)
( 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 Peter Dimov, 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.

Note: See TracTickets for help on using tickets.