mdbx: изменение log_if_error() ради устранения ложных "may be used uninitialized" предупреждений в LTO-сборках.

При включении LTO анализатор путей выполнения внутри GCC начинает укачивать из-за выражений вида `return LOG_IFERR(MDBX_EINVAL);`

Проблема в том, что несмотря на __builtin_assume() и __builtin_unreachable(), комплятор не хочет
видеть что функция log_if_error() всегда возвращает получаемое значение. А если допустить что значение
будет изменено, то вместо ошибки может быть MDBX_SUCCESS, и тогда в вызывающем как-бы может произойти
обращение к неинициализированным данным, что и беспокоит компилятор.

Например, при сборке mdbx_load:
  ‘txn_info.txn_space_dirty’ may be used uninitialized [-Wmaybe-uninitialized]

Проэтому проще пойти анализатору навстречу и упростить исходный код.
Теперь код ошибки явно пробрасывается через тело inline-функции, но это
требует 1-2 дополнительных процессорных инструкции на каждое применение
макроса LOG_IFERROR.

Также здесь откатывается коммит 81a8127084d9a6a7777bb375e029062330e51979.
This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2024-12-17 22:00:33 +03:00
parent ba6df2bb6d
commit e15079ec68
6 changed files with 37 additions and 72 deletions

View File

@ -361,17 +361,15 @@ __cold int mdbx_env_set_flags(MDBX_env *env, MDBX_env_flags_t flags, bool onoff)
return MDBX_SUCCESS;
}
__cold int mdbx_env_get_flags(const MDBX_env *env, unsigned *arg) {
if (unlikely(!arg))
__cold int mdbx_env_get_flags(const MDBX_env *env, unsigned *flags) {
int rc = check_env(env, false);
if (unlikely(rc != MDBX_SUCCESS))
return LOG_IFERR(rc);
if (unlikely(!flags))
return LOG_IFERR(MDBX_EINVAL);
int rc = check_env(env, false);
if (unlikely(rc != MDBX_SUCCESS)) {
*arg = 0;
return LOG_IFERR(rc);
}
*arg = env->flags & ENV_USABLE_FLAGS;
*flags = env->flags & ENV_USABLE_FLAGS;
return MDBX_SUCCESS;
}

View File

@ -197,22 +197,16 @@ int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
}
int mdbx_dbi_flags_ex(const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags, unsigned *state) {
if (unlikely(!flags || !state))
return LOG_IFERR(MDBX_EINVAL);
int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR - MDBX_TXN_PARKED);
if (unlikely(rc != MDBX_SUCCESS)) {
*flags = 0;
*state = 0;
if (unlikely(rc != MDBX_SUCCESS))
return LOG_IFERR(rc);
}
rc = dbi_check(txn, dbi);
if (unlikely(rc != MDBX_SUCCESS)) {
*flags = 0;
*state = 0;
if (unlikely(rc != MDBX_SUCCESS))
return LOG_IFERR(rc);
}
if (unlikely(!flags || !state))
return LOG_IFERR(MDBX_EINVAL);
*flags = txn->dbs[dbi].flags & DB_PERSISTENT_FLAGS;
*state = txn->dbi_state[dbi] & (DBI_FRESH | DBI_CREAT | DBI_DIRTY | DBI_STALE);
@ -230,41 +224,33 @@ static void stat_get(const tree_t *db, MDBX_stat *st, size_t bytes) {
}
__cold int mdbx_dbi_stat(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest, size_t bytes) {
if (unlikely(!dest))
return LOG_IFERR(MDBX_EINVAL);
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
if (unlikely(rc != MDBX_SUCCESS))
goto bailout;
return LOG_IFERR(rc);
rc = dbi_check(txn, dbi);
if (unlikely(rc != MDBX_SUCCESS))
goto bailout;
return LOG_IFERR(rc);
const size_t size_before_modtxnid = offsetof(MDBX_stat, ms_mod_txnid);
if (unlikely(bytes != sizeof(MDBX_stat)) && bytes != size_before_modtxnid) {
rc = MDBX_EINVAL;
goto bailout;
}
if (unlikely(txn->flags & MDBX_TXN_BLOCKED)) {
rc = MDBX_BAD_TXN;
goto bailout;
}
if (unlikely(txn->flags & MDBX_TXN_BLOCKED))
return LOG_IFERR(MDBX_BAD_TXN);
if (unlikely(txn->dbi_state[dbi] & DBI_STALE)) {
rc = tbl_fetch((MDBX_txn *)txn, dbi);
if (unlikely(rc != MDBX_SUCCESS))
goto bailout;
return LOG_IFERR(rc);
}
if (unlikely(!dest))
return LOG_IFERR(MDBX_EINVAL);
const size_t size_before_modtxnid = offsetof(MDBX_stat, ms_mod_txnid);
if (unlikely(bytes != sizeof(MDBX_stat)) && bytes != size_before_modtxnid)
return LOG_IFERR(MDBX_EINVAL);
dest->ms_psize = txn->env->ps;
stat_get(&txn->dbs[dbi], dest, bytes);
return MDBX_SUCCESS;
bailout:
memset(dest, 0, bytes);
return LOG_IFERR(rc);
}
__cold int mdbx_enumerate_tables(const MDBX_txn *txn, MDBX_table_enum_func *func, void *ctx) {

View File

@ -29,21 +29,17 @@ __cold int mdbx_is_readahead_reasonable(size_t volume, intptr_t redundancy) {
int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result, uint64_t increment) {
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
if (unlikely(rc != MDBX_SUCCESS)) {
bailout:
if (likely(result))
*result = ~UINT64_C(0);
if (unlikely(rc != MDBX_SUCCESS))
return LOG_IFERR(rc);
}
rc = dbi_check(txn, dbi);
if (unlikely(rc != MDBX_SUCCESS))
goto bailout;
return LOG_IFERR(rc);
if (unlikely(txn->dbi_state[dbi] & DBI_STALE)) {
rc = tbl_fetch(txn, dbi);
if (unlikely(rc != MDBX_SUCCESS))
goto bailout;
return LOG_IFERR(rc);
}
tree_t *dbs = &txn->dbs[dbi];

View File

@ -6,8 +6,8 @@
__cold int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi, uint32_t *mask) {
if (unlikely(!mask))
return LOG_IFERR(MDBX_EINVAL);
*mask = 0;
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
if (unlikely(rc != MDBX_SUCCESS))
return LOG_IFERR(rc);
@ -16,6 +16,7 @@ __cold int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi, uint32_
rc = cursor_init(&cx.outer, txn, dbi);
if (unlikely(rc != MDBX_SUCCESS))
return LOG_IFERR(rc);
if ((cx.outer.tree->flags & MDBX_DUPSORT) == 0)
return MDBX_RESULT_TRUE;
@ -50,15 +51,15 @@ __cold int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi, uint32_
}
int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary) {
if (unlikely(canary == nullptr))
return LOG_IFERR(MDBX_EINVAL);
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
if (unlikely(rc != MDBX_SUCCESS)) {
memset(canary, 0, sizeof(*canary));
return LOG_IFERR(rc);
}
if (unlikely(canary == nullptr))
return LOG_IFERR(MDBX_EINVAL);
*canary = txn->canary;
return MDBX_SUCCESS;
}

View File

@ -56,14 +56,13 @@ __cold void debug_log(int level, const char *function, int line, const char *fmt
va_end(args);
}
__cold int log_error(const int err, const char *func, unsigned line) {
__cold void log_error(const int err, const char *func, unsigned line) {
assert(err != MDBX_SUCCESS);
if (unlikely(globals.loglevel >= MDBX_LOG_DEBUG) &&
(globals.loglevel >= MDBX_LOG_TRACE || !(err == MDBX_RESULT_TRUE || err == MDBX_NOTFOUND))) {
char buf[256];
debug_log(MDBX_LOG_ERROR, func, line, "error %d (%s)\n", err, mdbx_strerror_r(err, buf, sizeof(buf)));
}
return err;
}
/* Dump a val in ascii or hexadecimal. */

View File

@ -148,27 +148,12 @@ MDBX_INTERNAL const char *pagetype_caption(const uint8_t type, char buf4unknown[
#define DVAL_DEBUG(x) ("-")
#endif
MDBX_INTERNAL int log_error(const int err, const char *func, unsigned line);
MDBX_INTERNAL void log_error(const int err, const char *func, unsigned line);
MDBX_MAYBE_UNUSED static inline int log_if_error(const int err, const char *func, unsigned line) {
if (likely(err == MDBX_SUCCESS))
if (unlikely(err != MDBX_SUCCESS))
log_error(err, func, line);
return err;
int rc = log_error(err, func, line);
#if __has_c_attribute(assume)
[[assume(rc == err && rc != MDBX_SUCCESS)]];
#endif
#if defined(__clang__) || __has_builtin(assume)
__builtin_assume(rc == err && rc != MDBX_SUCCESS);
#endif
if (rc != err || rc == MDBX_SUCCESS) {
#if defined(__GNUC__)
__builtin_unreachable();
#elif defined(_MSC_VER) && !defined(__clang__)
__assume(0);
#endif
rc = err;
}
return rc;
}
#define LOG_IFERR(err) log_if_error((err), __func__, __LINE__)