Add test helper macros. (#465)
- Refactor the existing SNMALLOC_ASSERT and SNMALLOC_CHECK. These now use the FatalErrorBuilder to format the output if a format string is provided. - Extend the FatalErrorBuilder to print decimal integers for signed values. - Rename FatalErrorBuilder to MessageBuilder. - Rewrite the macros used in the jemalloc tests to use FatalErrorBuilder and move them into a header. - Refactor some of the tests to use the new macros.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
// 28 is FAST_FAIL_INVALID_BUFFER_ACCESS. Not using the symbolic constant to
|
||||
@@ -109,27 +110,40 @@ namespace snmalloc
|
||||
#define TOSTRING2(expr) #expr
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define SNMALLOC_ASSERT(expr) \
|
||||
# define SNMALLOC_ASSERT_MSG(...) \
|
||||
{}
|
||||
#else
|
||||
# define SNMALLOC_ASSERT(expr) \
|
||||
# define SNMALLOC_ASSERT_MSG(expr, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (!(expr)) \
|
||||
{ \
|
||||
snmalloc::error("assert fail: " #expr " in " __FILE__ \
|
||||
" on " TOSTRING(__LINE__)); \
|
||||
snmalloc::report_fatal_error( \
|
||||
"assert fail: {} in {} on {} " fmt "\n", \
|
||||
#expr, \
|
||||
__FILE__, \
|
||||
TOSTRING(__LINE__), \
|
||||
##__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
} while (0)
|
||||
#endif
|
||||
#define SNMALLOC_ASSERT(expr) SNMALLOC_ASSERT_MSG(expr, "")
|
||||
|
||||
#define SNMALLOC_CHECK(expr) \
|
||||
#define SNMALLOC_CHECK_MSG(expr, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (!(expr)) \
|
||||
{ \
|
||||
snmalloc::error("Check fail: " #expr " in " __FILE__ \
|
||||
" on " TOSTRING(__LINE__)); \
|
||||
snmalloc::report_fatal_error( \
|
||||
"Check fail: {} in {} on {} " fmt "\n", \
|
||||
#expr, \
|
||||
__FILE__, \
|
||||
TOSTRING(__LINE__), \
|
||||
##__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
#define SNMALLOC_CHECK(expr) SNMALLOC_CHECK_MSG(expr, "")
|
||||
|
||||
#ifndef NDEBUG
|
||||
# define SNMALLOC_ASSUME(x) SNMALLOC_ASSERT(x)
|
||||
@@ -184,6 +198,13 @@ namespace snmalloc
|
||||
#else
|
||||
static constexpr bool CHECK_CLIENT = false;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Forward declaration so that this can be called before the pal header is
|
||||
* included.
|
||||
*/
|
||||
template<size_t BufferSize = 1024, typename... Args>
|
||||
[[noreturn]] inline void report_fatal_error(Args... args);
|
||||
} // namespace snmalloc
|
||||
|
||||
#ifdef SNMALLOC_CHECK_CLIENT
|
||||
|
||||
@@ -256,7 +256,7 @@ namespace snmalloc
|
||||
* build an on-stack buffer containing the formatted string.
|
||||
*/
|
||||
template<size_t BufferSize>
|
||||
class FatalErrorBuilder
|
||||
class MessageBuilder
|
||||
{
|
||||
/**
|
||||
* The buffer that is used to store the formatted output.
|
||||
@@ -322,17 +322,51 @@ namespace snmalloc
|
||||
*/
|
||||
void append(void* ptr)
|
||||
{
|
||||
append(static_cast<size_t>(reinterpret_cast<uintptr_t>(ptr)));
|
||||
append(static_cast<unsigned long long>(reinterpret_cast<uintptr_t>(ptr)));
|
||||
// TODO: CHERI bits.
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a signed integer to the buffer, as a decimal string.
|
||||
*/
|
||||
void append(long long s)
|
||||
{
|
||||
if (s < 0)
|
||||
{
|
||||
append_char('-');
|
||||
s = 0 - s;
|
||||
}
|
||||
std::array<char, 20> buf;
|
||||
const char digits[] = "0123456789";
|
||||
for (long i = long(buf.size() - 1); i >= 0; i--)
|
||||
{
|
||||
buf[static_cast<size_t>(i)] = digits[s % 10];
|
||||
s /= 10;
|
||||
}
|
||||
bool skipZero = true;
|
||||
for (auto c : buf)
|
||||
{
|
||||
if (skipZero && (c == '0'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
skipZero = false;
|
||||
append_char(c);
|
||||
}
|
||||
if (skipZero)
|
||||
{
|
||||
append_char('0');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a size to the buffer, as a hex string.
|
||||
*/
|
||||
void append(size_t s)
|
||||
void append(unsigned long long s)
|
||||
{
|
||||
append_char('0');
|
||||
append_char('x');
|
||||
std::array<char, sizeof(size_t) * 2> buf;
|
||||
std::array<char, 16> buf;
|
||||
const char hexdigits[] = "0123456789abcdef";
|
||||
// Length of string including null terminator
|
||||
static_assert(sizeof(hexdigits) == 0x11);
|
||||
@@ -357,12 +391,44 @@ namespace snmalloc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload to force `long` to be promoted to `long long`.
|
||||
*/
|
||||
void append(long x)
|
||||
{
|
||||
append(static_cast<long long>(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload to force `unsigned long` to be promoted to `unsigned long long`.
|
||||
*/
|
||||
void append(unsigned long x)
|
||||
{
|
||||
append(static_cast<unsigned long long>(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload to force `int` to be promoted to `long long`.
|
||||
*/
|
||||
void append(int x)
|
||||
{
|
||||
append(static_cast<long long>(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload to force `unsigned int` to be promoted to `unsigned long long`.
|
||||
*/
|
||||
void append(unsigned int x)
|
||||
{
|
||||
append(static_cast<unsigned long long>(x));
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor. Takes a format string and the arguments to output.
|
||||
*/
|
||||
template<typename... Args>
|
||||
SNMALLOC_FAST_PATH FatalErrorBuilder(const char* fmt, Args... args)
|
||||
SNMALLOC_FAST_PATH MessageBuilder(const char* fmt, Args... args)
|
||||
{
|
||||
buffer[SafeLength] = 0;
|
||||
size_t arg = 0;
|
||||
@@ -382,6 +448,21 @@ namespace snmalloc
|
||||
append_char('\0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for trivial format strings (no arguments). This exists to
|
||||
* allow `MessageBuilder` to be used with macros without special casing
|
||||
* the single-argument version.
|
||||
*/
|
||||
SNMALLOC_FAST_PATH MessageBuilder(const char* fmt)
|
||||
{
|
||||
buffer[SafeLength] = 0;
|
||||
for (const char* s = fmt; *s != 0; ++s)
|
||||
{
|
||||
append_char(*s);
|
||||
}
|
||||
append_char('\0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the error buffer.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user