]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: use try_lexical_convert instead of throwing lexical_cast 67585/head
authorKefu Chai <k.chai@proxmox.com>
Sun, 1 Mar 2026 04:16:40 +0000 (12:16 +0800)
committerKefu Chai <k.chai@proxmox.com>
Wed, 25 Mar 2026 23:22:20 +0000 (07:22 +0800)
rbd_features_from_string() uses boost::lexical_cast which throws
bad_lexical_cast when the input is not numeric. The exception is caught
and handled as "parse as feature name list instead".

This is normal control flow, but when ASAN's __cxa_throw interceptor is
misconfigured (e.g. with intercept_cxx_exceptions=0 leaving real___cxa_throw
NULL), any exception causes a CHECK failure. Even with a correctly configured
ASAN, throwing exceptions during config initialization adds overhead.

Replace the try/catch pattern with boost::conversion::try_lexical_convert,
which returns false on parse failure instead of throwing. This eliminates
the exception entirely, making the code more efficient and avoiding any
interaction with ASAN's exception interceptor.

The ASan report:

```
AddressSanitizer: CHECK failed: asan_interceptors.cpp:320 "((__interception::real___cxa_throw)) != (0)" (0x0, 0x0) (tid=30529)
    #0 0x7d668fac9a09 in CheckUnwind ../../../../src/libsanitizer/asan/asan_rtl.cpp:67
    #1 0x7d668faec105 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) ../../../../src/libsanitizer/sanitizer_common/sanitizer_termination.cpp:86
    #2 0x7d668fa4b194 in __interceptor___cxa_throw ../../../../src/libsanitizer/asan/asan_interceptors.cpp:320
    #3 0x7d668ae4ec0f in void boost::throw_exception<boost::bad_lexical_cast>(boost::bad_lexical_cast const&) /opt/ceph/include/boost/throw_exception.hpp:165
    #4 0x7d668c1e1e0b in void boost::conversion::detail::throw_bad_cast<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long>() /opt/ceph/include/boost/lexical_cast/bad_lexical_cast.hpp:93
    #5 0x7d668c1e0e05 in unsigned long boost::lexical_cast<unsigned long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /opt/ceph/include/boost/lexical_cast.hpp:43
    #6 0x7d668c1df609 in librbd::rbd_features_from_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::ostream*) /ceph/src/librbd/Features.cc:67
    #7 0x7d668b255a35 in get_rbd_options()::$_2::operator()(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) const src/common/options/rbd_options.cc:44
    #8 0x7d668b255806 in int std::__invoke_impl<int, get_rbd_options()::$_2&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*>(std::__invoke_other, get_rbd_options()::$_2&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*&&) /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61
    #9 0x7d668b255754 in std::enable_if<is_invocable_r_v<int, get_rbd_options()::$_2&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*>, int>::type std::__invoke_r<int, get_rbd_options()::$_2&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*>(get_rbd_options()::$_2&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*&&) /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:114
    #10 0x7d668b25563c in std::_Function_handler<int (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*), get_rbd_options()::$_2>::_M_invoke(std::_Any_data const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*&&) /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290
    #11 0x7d668af924f1 in std::function<int (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*)>::operator()(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) const /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591
    #12 0x7d668af8c495 in Option::pre_validate(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) const /ceph/src/common/options.cc:94
    #13 0x7d668aef9ec3 in md_config_t::md_config_t(ConfigValues&, ConfigTracker const&, bool) /ceph/src/common/config.cc:208
    #14 0x7d668ae0040d in ceph::common::ConfigProxy::ConfigProxy(bool) /ceph/src/common/config_proxy.h:70
    #15 0x7d668adf3f5d in ceph::common::CephContext::CephContext(unsigned int, ceph::common::CephContext::create_options const&) /ceph/src/common/ceph_context.cc:730
    #16 0x7d668adf3785 in ceph::common::CephContext::CephContext(unsigned int, code_environment_t, int) /ceph/src/common/ceph_context.cc:724
    #17 0x7d668aef5ee6 in common_preinit(CephInitParameters const&, code_environment_t, int) /ceph/src/common/common_init.cc:40
    #18 0x7d668d4a47af in rados_create_cct(char const*, CephInitParameters*) /ceph/src/librados/librados_c.cc:120
    #19 0x7d668d4a49db in _rados_create2 /ceph/src/librados/librados_c.cc:168
    #20 0x7d668d94dc4b in __pyx_pf_5rados_5Rados_2__setup /ceph/build/src/pybind/rados/rados_processed.c:13219
    #21 0x7d668d94dc4b in __pyx_pw_5rados_5Rados_3__setup /ceph/build/src/pybind/rados/rados_processed.c:12703
    #22 0x7d668d94a347 in __Pyx_CyFunction_CallAsMethod /ceph/build/src/pybind/rados/rados_processed.c:93157
    #23 0x58ac5086d0ba in _PyObject_MakeTpCall (/usr/bin/python3.10+0x1810ba)
    #24 0x58ac508843da  (/usr/bin/python3.10+0x1983da)
    #25 0x58ac50885076 in PyVectorcall_Call (/usr/bin/python3.10+0x199076)
    #26 0x7d668d94cdd7 in __Pyx_PyObject_Call /ceph/build/src/pybind/rados/rados_processed.c:90994
    #27 0x7d668d94cdd7 in __pyx_pf_5rados_5Rados___init__ /ceph/build/src/pybind/rados/rados_processed.c:12474
    #28 0x7d668d94cdd7 in __pyx_pw_5rados_5Rados_1__init__ /ceph/build/src/pybind/rados/rados_processed.c:12443
    #29 0x58ac5086d43a  (/usr/bin/python3.10+0x18143a)
    #30 0x58ac50884d3a in PyObject_Call (/usr/bin/python3.10+0x198d3a)
    #31 0x58ac508637de in _PyEval_EvalFrameDefault (/usr/bin/python3.10+0x1777de)
    #32 0x58ac5087702b in _PyFunction_Vectorcall (/usr/bin/python3.10+0x18b02b)
    #33 0x58ac508615fe in _PyEval_EvalFrameDefault (/usr/bin/python3.10+0x1755fe)
    #34 0x58ac5087702b in _PyFunction_Vectorcall (/usr/bin/python3.10+0x18b02b)
    #35 0x58ac508615fe in _PyEval_EvalFrameDefault (/usr/bin/python3.10+0x1755fe)
```

Signed-off-by: Kefu Chai <k.chai@proxmox.com>
src/librbd/Features.cc
src/librbd/io/IoOperations.cc

index 71cc8b374e04e382e225982f2e728a2de52e3669..005c9bc397cc7e2811368fceee4dd5078555c9cc 100644 (file)
@@ -1,8 +1,8 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
 // vim: ts=8 sw=2 sts=2 expandtab
 
-#include <boost/lexical_cast.hpp>
 #include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast/try_lexical_convert.hpp>
 
 #include "librbd/Features.h"
 #include "include/rbd/features.h"
@@ -62,10 +62,8 @@ uint64_t rbd_features_from_string(const std::string& orig_value,
     return RBD_FEATURES_DEFAULT;
   }
 
-  try {
-    // numeric?
-    features = boost::lexical_cast<uint64_t>(value);
-
+  // Try to parse as numeric value first
+  if (boost::conversion::try_lexical_convert(value, features)) {
     // drop unrecognized bits
     uint64_t unsupported_features = (features & ~RBD_FEATURES_ALL);
     if (unsupported_features != 0ull) {
@@ -85,7 +83,7 @@ uint64_t rbd_features_from_string(const std::string& orig_value,
        *err << "ignoring feature mask 0x" << std::hex << ignored_features;
       }
     }
-  } catch (boost::bad_lexical_cast&) {
+  } else {
     // feature name list?
     bool errors = false;
     std::vector<std::string> feature_names;
index 855f9875d7aab6c1504abebd7c8967540b5b4948..b2006ab9fa476ff7034a95bdad4ed381fa949e92 100644 (file)
@@ -1,8 +1,8 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
 // vim: ts=8 sw=2 sts=2 expandtab
 
-#include <boost/lexical_cast.hpp>
 #include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast/try_lexical_convert.hpp>
 
 #include "librbd/io/Types.h"
 #include "librbd/io/IoOperations.h"
@@ -61,10 +61,8 @@ uint64_t rbd_io_operations_from_string(const std::string& orig_value,
     return RBD_IO_OPERATIONS_DEFAULT;
   }
 
-  try {
-    // numeric?
-    operations = boost::lexical_cast<uint64_t>(value);
-
+  // Try to parse as numeric value first
+  if (boost::conversion::try_lexical_convert(value, operations)) {
     // drop unrecognized bits
     uint64_t unsupported_operations = (operations & ~RBD_IO_OPERATIONS_ALL);
     if (unsupported_operations != 0ull) {
@@ -74,7 +72,7 @@ uint64_t rbd_io_operations_from_string(const std::string& orig_value,
              << std::hex << unsupported_operations << std::dec;
       }
     }
-  } catch (boost::bad_lexical_cast&) {
+  } else {
     // operation name list?
     bool errors = false;
     std::vector<std::string> operation_names;