Skip to content

Commit 04f76e0

Browse files
authored
Merge pull request ceph#62294 from rzarzynski/wip-bypassable-ceph-assert
common, *: make the abort() in ceph_assert() bypassable Reviewed-by: Radoslaw Zarzynski <[email protected]> Reviewed-by: Adam Kupczyk <[email protected]> Reviewed-by: Laura Flores <[email protected]> Reviewed-by: Matan Breizman <[email protected]>
2 parents aafd5c5 + adcf7ff commit 04f76e0

File tree

15 files changed

+145
-37
lines changed

15 files changed

+145
-37
lines changed

src/common/assert.cc

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <sstream>
1818

1919
#include "include/compat.h"
20+
#include "include/str_list.h"
2021
#include "common/BackTrace.h"
2122
#include "common/Clock.h" // for ceph_clock_now()
2223
#include "common/debug.h"
@@ -42,6 +43,12 @@ namespace ceph {
4243
{
4344
ceph_assert(!g_assert_context);
4445
g_assert_context = cct;
46+
const auto supressions = get_str_list(
47+
g_assert_context->_conf.get_val<std::string>("ceph_assert_supresssions"));
48+
if (!supressions.empty()) {
49+
lderr(g_assert_context) << "WARNING: supressions for ceph_assert present: "
50+
<< supressions << dendl;
51+
}
4552
}
4653

4754
[[gnu::cold]] void __ceph_assert_fail(const char *assertion,
@@ -70,6 +77,7 @@ namespace ceph {
7077
oss << ClibBackTrace(1);
7178
dout_emergency(oss.str());
7279

80+
bool should_abort = true;
7381
if (g_assert_context) {
7482
lderr(g_assert_context) << g_assert_msg << std::endl;
7583
*_dout << oss.str() << dendl;
@@ -78,9 +86,22 @@ namespace ceph {
7886
if (!g_assert_context->_conf->fatal_signal_handlers) {
7987
g_assert_context->_log->dump_recent();
8088
}
81-
}
8289

83-
abort();
90+
// bypass the abort?
91+
const auto supressions = get_str_list(
92+
g_assert_context->_conf.get_val<std::string>("ceph_assert_supresssions"));
93+
should_abort = std::none_of(
94+
std::begin(supressions), std::end(supressions),
95+
[file, line](const auto& supression) {
96+
return supression == fmt::format("{}:{}", file, line);
97+
});
98+
}
99+
if (should_abort) {
100+
abort();
101+
} else {
102+
dout_emergency("WARNING: ceph_assert() does NOT abort() due "
103+
"to ceph_assert_supresssions");
104+
}
84105
}
85106

86107
[[gnu::cold]] void __ceph_assert_fail(const assert_data &ctx)
@@ -151,6 +172,7 @@ namespace ceph {
151172
oss << *bt;
152173
dout_emergency(oss.str());
153174

175+
bool should_abort = true;
154176
if (g_assert_context) {
155177
lderr(g_assert_context) << g_assert_msg << std::endl;
156178
*_dout << oss.str() << dendl;
@@ -159,9 +181,22 @@ namespace ceph {
159181
if (!g_assert_context->_conf->fatal_signal_handlers) {
160182
g_assert_context->_log->dump_recent();
161183
}
162-
}
163184

164-
abort();
185+
// bypass the abort?
186+
const auto supressions = get_str_list(
187+
g_assert_context->_conf.get_val<std::string>("ceph_assert_supresssions"));
188+
should_abort = std::none_of(
189+
std::begin(supressions), std::end(supressions),
190+
[file, line](const auto& supression) {
191+
return supression == fmt::format("{}:{}", file, line);
192+
});
193+
}
194+
if (should_abort) {
195+
abort();
196+
} else {
197+
dout_emergency("WARNING: ceph_assertf() does NOT abort() due to"
198+
"to ceph_assert_supresssions");
199+
}
165200
}
166201

167202
[[gnu::cold]] void __ceph_abort(const char *file, int line,

src/common/options/global.yaml.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6718,3 +6718,10 @@ options:
67186718
desc: Enables exception throwing instead of process abort on transaction submission error.
67196719
default: false
67206720
with_legacy: false
6721+
- name: ceph_assert_supresssions
6722+
type: str
6723+
desc: Suppress specific ceph_assert instances to let the execution continue with unknown, potentially DESTRUCTIVE consequences.
6724+
fmt_desc: Comma-separated list of locations of ceph_assert in the source code.
6725+
The format is ``{file}:{line} [, {file}:{line}]``
6726+
level: dev
6727+
with_legacy: false

src/common/perf_histogram.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ void PerfHistogramCommon::dump_formatted_axis(
3333
f->dump_string("scale_type", "log2");
3434
break;
3535
default:
36-
ceph_assert(false && "Invalid scale type");
36+
ceph_abort_msg("Invalid scale type");
3737
}
3838

3939
{
@@ -63,7 +63,7 @@ int64_t get_quants(int64_t i, PerfHistogramCommon::scale_type_d st) {
6363
case PerfHistogramCommon::SCALE_LOG2:
6464
return int64_t(1) << (i - 1);
6565
}
66-
ceph_assert(false && "Invalid scale type");
66+
ceph_abort_msg("Invalid scale type");
6767
}
6868

6969
int64_t PerfHistogramCommon::get_bucket_for_axis(
@@ -87,7 +87,7 @@ int64_t PerfHistogramCommon::get_bucket_for_axis(
8787
}
8888
return ac.m_buckets - 1;
8989
}
90-
ceph_assert(false && "Invalid scale type");
90+
ceph_abort_msg("Invalid scale type");
9191
}
9292

9393
std::vector<std::pair<int64_t, int64_t>>

src/crimson/os/alienstore/alien_store.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ auto AlienStore::omap_get_header(CollectionRef ch,
638638
return crimson::ct_error::enoent::make();
639639
} else if (r < 0) {
640640
logger().error("omap_get_header: {}", r);
641-
ceph_assert(0 == "impossible");
641+
ceph_abort_msg("impossible");
642642
} else {
643643
return get_attr_errorator::make_ready_future<ceph::bufferlist>(
644644
std::move(bl));

src/crimson/osd/scheduler/mclock_scheduler.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,12 @@ item_t mClockScheduler::dequeue()
123123
} else {
124124
mclock_queue_t::PullReq result = scheduler.pull_request();
125125
if (result.is_future()) {
126-
ceph_assert(
127-
0 == "Not implemented, user would have to be able to be woken up");
126+
ceph_abort_msg(
127+
"Not implemented, user would have to be able to be woken up");
128128
return std::move(*(item_t*)nullptr);
129129
} else if (result.is_none()) {
130-
ceph_assert(
131-
0 == "Impossible, must have checked empty() first");
130+
ceph_abort_msg(
131+
"Impossible, must have checked empty() first");
132132
return std::move(*(item_t*)nullptr);
133133
} else {
134134
ceph_assert(result.is_retn());

src/include/ceph_assert.h

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,14 @@ struct assert_data {
5050
const char *function;
5151
};
5252

53-
extern void __ceph_assert_fail(const char *assertion, const char *file, int line, const char *function)
54-
__attribute__ ((__noreturn__));
55-
extern void __ceph_assert_fail(const assert_data &ctx)
56-
__attribute__ ((__noreturn__));
53+
extern void __ceph_assert_fail(const char *assertion, const char *file, int line, const char *function);
54+
extern void __ceph_assert_fail(const assert_data &ctx);
55+
template <const assert_data* AssertCtxV>
56+
[[gnu::noinline, gnu::cold]] static void __ceph_assert_fail() {
57+
__ceph_assert_fail(*AssertCtxV);
58+
}
5759

58-
extern void __ceph_assertf_fail(const char *assertion, const char *file, int line, const char *function, const char* msg, ...)
59-
__attribute__ ((__noreturn__));
60+
extern void __ceph_assertf_fail(const char *assertion, const char *file, int line, const char *function, const char* msg, ...);
6061
extern void __ceph_assert_warn(const char *assertion, const char *file, int line, const char *function);
6162

6263
[[noreturn]] void __ceph_abort(const char *file, int line, const char *func,
@@ -101,11 +102,14 @@ using namespace ceph;
101102
} while (false)
102103
#else
103104
#define ceph_assert(expr) \
104-
do { static const ceph::assert_data assert_data_ctx = \
105-
{__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION}; \
106-
((expr) \
107-
? _CEPH_ASSERT_VOID_CAST (0) \
108-
: ::ceph::__ceph_assert_fail(assert_data_ctx)); } while(false)
105+
do { \
106+
static const auto func_name = __CEPH_ASSERT_FUNCTION; \
107+
[] (const bool eval) { \
108+
static const ceph::assert_data assert_data_ctx = \
109+
{__STRING(expr), __FILE__, __LINE__, func_name}; \
110+
((eval) \
111+
? _CEPH_ASSERT_VOID_CAST (0) \
112+
: ::ceph::__ceph_assert_fail<&assert_data_ctx>()); }((bool)(expr)); } while(false)
109113
#endif
110114

111115
// this variant will *never* get compiled out to NDEBUG in the future.
@@ -119,11 +123,14 @@ using namespace ceph;
119123
} while(false)
120124
#else
121125
#define ceph_assert_always(expr) \
122-
do { static const ceph::assert_data assert_data_ctx = \
123-
{__STRING(expr), __FILE__, __LINE__, __CEPH_ASSERT_FUNCTION}; \
124-
((expr) \
125-
? _CEPH_ASSERT_VOID_CAST (0) \
126-
: ::ceph::__ceph_assert_fail(assert_data_ctx)); } while(false)
126+
do { \
127+
static const auto func_name = __CEPH_ASSERT_FUNCTION; \
128+
[] (const bool eval) { \
129+
static const ceph::assert_data assert_data_ctx = \
130+
{__STRING(expr), __FILE__, __LINE__, func_name}; \
131+
((eval) \
132+
? _CEPH_ASSERT_VOID_CAST (0) \
133+
: ::ceph::__ceph_assert_fail<&assert_data_ctx>()); }((bool)(expr)); } while(false)
127134
#endif
128135

129136
// Named by analogy with printf. Along with an expression, takes a format

src/librbd/crypto/CryptoContextPool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class CryptoContextPool : public DataCryptor<T> {
5757
case CIPHER_MODE_DEC:
5858
return m_decrypt_contexts;
5959
default:
60-
ceph_assert(false);
60+
ceph_abort();
6161
}
6262
}
6363
};

src/mon/Monitor.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4193,10 +4193,10 @@ struct AnonConnection : public Connection {
41934193
entity_addr_t socket_addr;
41944194

41954195
int send_message(Message *m) override {
4196-
ceph_assert(!"send_message on anonymous connection");
4196+
ceph_abort_msg("send_message on anonymous connection");
41974197
}
41984198
void send_keepalive() override {
4199-
ceph_assert(!"send_keepalive on anonymous connection");
4199+
ceph_abort_msg("send_keepalive on anonymous connection");
42004200
}
42014201
void mark_down() override {
42024202
// silently ignore

src/os/bluestore/BlueStore.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10175,7 +10175,7 @@ class ShallowFSCKThreadPool : public ThreadPool
1017510175
}
1017610176
/// Check whether there is anything to do.
1017710177
bool _empty() override {
10178-
ceph_assert(false);
10178+
ceph_abort();
1017910179
}
1018010180

1018110181
/// Get the next work item to process.
@@ -10242,7 +10242,7 @@ class ShallowFSCKThreadPool : public ThreadPool
1024210242
* so at most one copy will execute simultaneously for a given thread pool.
1024310243
* It can be used for non-thread-safe finalization. */
1024410244
void _void_process_finish(void*) override {
10245-
ceph_assert(false);
10245+
ceph_abort();
1024610246
}
1024710247

1024810248
bool queue(

src/os/bluestore/bluestore_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ struct bluestore_blob_t {
10521052
}
10531053
loc -= e.length;
10541054
}
1055-
ceph_assert(false);
1055+
ceph_abort();
10561056
};
10571057

10581058
/// updates blob's pextents container and return unused pextents eligible

0 commit comments

Comments
 (0)