asserted(inBuffer==nullptr,
"Unexpected non null input buffer", inBuffer, inBufferSize, !cmDecompressor);asserted is a library making a trade-off between weight and features:
- lighter is the standard library
- full featured is for instance libassert
It eases C++ development at low cost by bringing much needed features.
- Context display via variable content
- Stacktrace dump (requires libunwind to build on Linux, and addr2line at run time for symbol resolution)
- Signals override to catch crashes
- Automatic breakpoint in an attached debugger on crash
- Compile-time enabling of group of assertions
- No "unused variable" when assertions are disabled
- Single header
- Linux & Windows support
-
Direct method: copy the single
asserted.hinside your project -
CMake method: install the library on your system:
mkdir build && cd build && cmake .. && make install
and declare it in your project's CMakeLists.txt with find_package(asserted)
The full API is made of 3 variants:
// Assertion with possibility to pass context variables
asserted(cond, ...);
// Variant which depends on the NDEBUG flag (as standard assert)
debug_asserted(cond, ...);
// Variant which is enabled per group
group_asserted(group_name, cond, ...); All of them:
- dump the content of the provided context variables
- Supports integral types, pointers and std::string
- dump the stacktrace if enabled
- Enabled by default on Windows
- On Linux, requires
libunwind-devat build time and the compilation flagASSERTED_WITH_STACKTRACE=1, plusaddr2linereachable on$PATHat run time to resolve addresses into function names and file:line (falls back to raw addresses otherwise - see Optional dependencies)
- are fully removed at compile time if disabled
// Equivalent to standard assertions (therefore subjected to NDEBUG)
debug_asserted(a == b);
// Enhanced with some context variables, evaluated only if the assertion fails
asserted(a == b, a, b, this, std::sin(a));
// The result of this one is shown below
asserted(idx < size, "Out of bound", idx, size);Groups of assertions can be selectively disabled:
// The value of 1 enables the group, 0 disables it at compile-time (no run-time cost)
#define ASSERTED_GROUP_ENGINE 1
group_asserted(ENGINE, a == b);
// The result of this one is shown below
group_asserted(ENGINE, a == b, "Please refer to requirement 314P", a, b);If signals catching is not disabled, just including the library is enough to enable the feature.
Below is an example:
The library is configured through compile time flags:
| Flag Name | Description | Default |
|---|---|---|
| ASSERTED_WITH_STACKTRACE | Enable the stacktrace dump if set to 1 | 0 on Linux 1 on Windows |
| ASSERTED_NO_ASSERT | Disable all assertions at compile time if set to 1 | 0 (assertions enabled) |
| ASSERTED_NO_SIGNALS | Disable the signal catching if set to 1 | 0 (signals caught) |
| ASSERTED_NO_SIGINT | Disable the SIGINT signal catching if set to 1 | 0 (sigint handled) |
| ASSERTED_NO_DEBUG_BREAK | Disable automatically breaking into an attached debugger on crash if set to 1 | 0 (enabled) |
| ASSERTED_NO_COLOR | Disable the terminal colors if set to 1 | 0 (colored dump) |
| ASSERTED_CRASH_MSG_SIZE | Max size in bytes of the formatted crash message | 2048 |
| ASSERTED_ALT_STACK_SIZE | Size in bytes of the alternate signal stack (Linux/Unix), used so a SIGSEGV from stack overflow still has room to run the handler | 262144 (256 KiB) |
| ASSERTED_ADDR2LINE_BIN | Binary used on Linux/Unix to resolve stacktrace addresses (looked up via $PATH, or pass an absolute path) |
"addr2line" |
libunwind-dev library to be present at build time,
and the addr2line command to be present on $PATH at run time (see
Optional dependencies) for function names and file:line to be resolved. Without it,
frames are still caught and printed, just as raw addresses.
The purpose of such benchmark is mainly to check on the weight of the library. It was run on an average laptop.
Raw results from the internal benchmark (run test/run_suite.py -s performance):
===================================================================================
| asserted - Header include | 0.126 s |
| asserted - Header include - fully disabled | 0.000 s |
| asserted - Library code size (-O2) | 0 bytes |
| asserted - assertion code size 0 variable (-O2) | 12 bytes/log |
| asserted - assertion code size 1 variable (-O2) | 60 bytes/log |
| asserted - assertion code size 4 variables (-O2) | 132 bytes/log |
| asserted - assertion compilation speed (-O0) | 4613 log/s |
| asserted - assertion compilation speed (-O2) | 3291 log/s |
| asserted - assertion runtime 0 variable | 0.12 ns or 8343.6 Mlog/s |
| asserted - assertion runtime 1 variable | 0.12 ns or 8448.5 Mlog/s |
| asserted - assertion runtime 4 variables | 0.12 ns or 8162.5 Mlog/s |
===================================================================================
I do not see the logged stracktrace when a crash occurs
Displaying the stack trace at all requires two conditions: - presence of the stacktrace library at build time (native on Windows, `libunwind-dev` on Linux) - presence of the ASSERTED_WITH_STACKTRACE=1 directive as a compilation flag (for *every* compilation units)
On Linux, function names and file:line additionally require addr2line to be reachable on $PATH at the time of
the crash (see Optional dependencies); without it, the frames are still printed, just as
raw addresses instead.
Does the automatic debugger breakpoint do anything when not running under a debugger?
No. It is only ever triggered after actively checking that a debugger is attached (`IsDebuggerPresent()` on Windows, the `TracerPid` field of `/proc/self/status` on Linux/Unix) - a normal, undebugged run never raises anything and is completely unaffected. On Linux, a defensive fallback signal handler is additionally installed so that even if the check's assumption were ever wrong, the process would simply continue rather than being killed. Set `ASSERTED_NO_DEBUG_BREAK=1` to disable the feature entirely.
There are many compilation errors about ASSERTED_PRIV_IF(...) and asserteg(...)
The requirement to fully remove the code related to assertions at compile time implies using macros, so that the library is also efficient without optimization.
Using a group of assertion has a strong requirement: the group name must be defined, else a cascade of errors indeed appears.
Just check that the group is properly defined in all cases and that it has the desired value: 0 for disabled, 1 for enabled.
No dependency, with one exception: displaying the stacktrace on Linux involves two things, one at build time and one at run time.
- Build time: the
libunwindlibrary, needed to capture raw return addresses. Add it withapt install libunwind-devon Ubuntu. - Run time: the
addr2linecommand (part of binutils,apt install binutilson Ubuntu - usually already present), used to resolve those addresses into function names and file:line. This is a deliberate design choice: resolving addresses in-process (as this library used to, and as libdw-based tools still do) means calling into code that allocates memory from inside the crash handler itself, which risks a deadlock if the crash was itself caused by heap corruption. Spawningaddr2lineas a short-lived subprocess avoids that, at the cost of it having to be present on whichever machine the crash actually happens on, not just the one the code was built on. If it isn't found, or fails for any reason, the stacktrace still gets printed - just as raw addresses instead of resolved ones.ASSERTED_ADDR2LINE_BIN(see Configuration) overrides the binary name/path used, ifaddr2lineisn't reachable via$PATHor a different tool is preferred.
Released under the MIT license



