From 4eac5187db6b907a54902f569fe898d9312d2134 Mon Sep 17 00:00:00 2001 From: Adam Crume Date: Fri, 18 Jul 2014 12:06:19 -0700 Subject: [PATCH] Add assertf macro Signed-off-by: Adam Crume --- src/common/assert.cc | 69 ++++++++++++++++++++++++++++++++++++++++++++ src/include/assert.h | 8 +++++ 2 files changed, 77 insertions(+) diff --git a/src/common/assert.cc b/src/common/assert.cc index 7889ad043a692..67c43df1b782e 100644 --- a/src/common/assert.cc +++ b/src/common/assert.cc @@ -77,6 +77,75 @@ namespace ceph { throw FailedAssertion(bt); } + void __ceph_assertf_fail(const char *assertion, const char *file, int line, const char *func, const char* msg, ...) + { + ostringstream tss; + tss << ceph_clock_now(g_assert_context); + + class BufAppender { + public: + BufAppender(char* buf, int size) : bufptr(buf), remaining(size) { + } + + void printf(const char * format, ...) { + va_list args; + va_start(args, format); + this->vprintf(format, args); + va_end(args); + } + + void vprintf(const char * format, va_list args) { + int n = vsnprintf(bufptr, remaining, format, args); + if (n >= 0) { + if (n < remaining) { + remaining -= n; + bufptr += n; + } else { + remaining = 0; + } + } + } + + private: + char* bufptr; + int remaining; + }; + + char buf[8096]; + BufAppender ba(buf, sizeof(buf)); + BackTrace *bt = new BackTrace(1); + ba.printf("%s: In function '%s' thread %llx time %s\n" + "%s: %d: FAILED assert(%s)\n", + file, func, (unsigned long long)pthread_self(), tss.str().c_str(), + file, line, assertion); + ba.printf("Assertion details: "); + va_list args; + va_start(args, msg); + ba.vprintf(msg, args); + va_end(args); + ba.printf("\n"); + dout_emergency(buf); + + // TODO: get rid of this memory allocation. + ostringstream oss; + bt->print(oss); + dout_emergency(oss.str()); + + dout_emergency(" NOTE: a copy of the executable, or `objdump -rdS ` " + "is needed to interpret this.\n"); + + if (g_assert_context) { + lderr(g_assert_context) << buf << std::endl; + bt->print(*_dout); + *_dout << " NOTE: a copy of the executable, or `objdump -rdS ` " + << "is needed to interpret this.\n" << dendl; + + g_assert_context->_log->dump_recent(); + } + + throw FailedAssertion(bt); + } + void __ceph_assert_warn(const char *assertion, const char *file, int line, const char *func) { diff --git a/src/include/assert.h b/src/include/assert.h index 5ff41ba69d7a3..ec0aa34d601f8 100644 --- a/src/include/assert.h +++ b/src/include/assert.h @@ -68,6 +68,8 @@ struct FailedAssertion { extern void register_assert_context(CephContext *cct); extern void __ceph_assert_fail(const char *assertion, const char *file, int line, const char *function) __attribute__ ((__noreturn__)); +extern void __ceph_assertf_fail(const char *assertion, const char *file, int line, const char *function, const char* msg, ...) + __attribute__ ((__noreturn__)); extern void __ceph_assert_warn(const char *assertion, const char *file, int line, const char *function); #define ceph_assert(expr) \ @@ -138,3 +140,9 @@ using namespace ceph; ? __CEPH_ASSERT_VOID_CAST (0) \ : __ceph_assert_fail (__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION)) +// Named by analogy with printf. Along with an expression, takes a format +// string and parameters which are printed if the assertion fails. +#define assertf(expr, ...) \ + ((expr) \ + ? __CEPH_ASSERT_VOID_CAST (0) \ + : __ceph_assertf_fail (__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION, __VA_ARGS__)) -- 2.39.5