Skip to content

function argument safety check silently optimized out in release build by clang #5048

@risa2000

Description

@risa2000

Description

With clang 21.1.8 on macOS, or clang-cl.exe 21.1.8 on Windows the release build of unit test test-class_parser_cpp11 (tests/src/unit-class_parser.cpp) crashes with an unhandled exception (SIGSEGV on macOS, Access violation on Windows).

The reason why it crashes is that in release build the compiler optimizes out the safety check here:

if (sax == nullptr)

Normally, there would be a warning emitted by the compiler:

/Users/risa/Dev/LLVM/bin/clang++ -DDOCTEST_CONFIG_SUPER_FAST_ASSERTS -DJSON_TEST_KEEP_MACROS -DJSON_TEST_USING_MULTIPLE_HEADERS=1 -I/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/thirdparty/doctest -I/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/thirdparty/fifo_map -I/Users/risa/Work_OSS/_risa2000/nlohmann_json/out/build/arm64_RelWithDebInfo/include -I/Users/risa/Work_OSS/_risa2000/nlohmann_json/include -O2 -g -DNDEBUG -std=gnu++11 -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -Wno-deprecated -Wno-float-equal -o tests/CMakeFiles/test-class_parser_cpp11.dir/src/unit-class_parser.cpp.o -c /Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/src/unit-class_parser.cpp
In file included from /Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/src/unit-class_parser.cpp:12:
/Users/risa/Work_OSS/_risa2000/nlohmann_json/include/nlohmann/json.hpp:4132:13: warning: comparison of nonnull parameter 'sax' equal to a null pointer is 'false' on first
      encounter [-Wtautological-pointer-compare]
 4132 |         if (sax == nullptr)
      |             ^~~    ~~~~~~~
/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/src/unit-class_parser.cpp:224:11: note: in instantiation of function template specialization
      'nlohmann::basic_json<>::sax_parse<const std::string &, nlohmann::detail::json_sax_dom_parser<nlohmann::basic_json<>, nlohmann::detail::iterator_input_adapter<std::__wrap_iter<const char
      *>>>>' requested here
  224 |     json::sax_parse(s, &sdp);
      |           ^
/Users/risa/Work_OSS/_risa2000/nlohmann_json/include/nlohmann/json.hpp:4118:5: note: declared 'nonnull' here
 4118 |     JSON_HEDLEY_NON_NULL(2)
      |     ^
/Users/risa/Work_OSS/_risa2000/nlohmann_json/include/nlohmann/thirdparty/hedley/hedley.hpp:1287:54: note: expanded from macro 'JSON_HEDLEY_NON_NULL'
 1287 |     #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
      |                                                      ^
In file included from /Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/src/unit-class_parser.cpp:12:
/Users/risa/Work_OSS/_risa2000/nlohmann_json/include/nlohmann/json.hpp:4132:13: warning: comparison of nonnull parameter 'sax' equal to a null pointer is 'false' on first
      encounter [-Wtautological-pointer-compare]
 4132 |         if (sax == nullptr)
      |             ^~~    ~~~~~~~
/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/src/unit-class_parser.cpp:251:25: note: in instantiation of function template specialization
      'nlohmann::basic_json<>::sax_parse<const std::string &, (anonymous namespace)::SaxEventLogger>' requested here
  251 |     CHECK_NOTHROW(json::sax_parse(s, &el, json::input_format_t::json, false));
      |                         ^
/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/thirdparty/doctest/doctest.h:2976:50: note: expanded from macro 'CHECK_NOTHROW'
 2976 | #define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__)
      |                                                  ^
/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/thirdparty/doctest/doctest.h:2544:77: note: expanded from macro 'DOCTEST_CHECK_NOTHROW'
 2544 | #define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__)
      |                                                                             ^
/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/thirdparty/doctest/doctest.h:2521:34: note: expanded from macro 'DOCTEST_ASSERT_NOTHROW'
 2521 |             DOCTEST_CAST_TO_VOID(__VA_ARGS__)                                                      \
      |                                  ^
/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/thirdparty/doctest/doctest.h:2154:23: note: expanded from macro 'DOCTEST_CAST_TO_VOID'
 2154 |     static_cast<void>(__VA_ARGS__);                                                                \
      |                       ^
/Users/risa/Work_OSS/_risa2000/nlohmann_json/include/nlohmann/json.hpp:4118:5: note: declared 'nonnull' here
 4118 |     JSON_HEDLEY_NON_NULL(2)
      |     ^
/Users/risa/Work_OSS/_risa2000/nlohmann_json/include/nlohmann/thirdparty/hedley/hedley.hpp:1287:54: note: expanded from macro 'JSON_HEDLEY_NON_NULL'
 1287 |     #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
      |                                                      ^

but the warning -Wtautological-pointer-compare is silenced in the library code, and it seems this warning is actually trying to warn about this.

The debug build does not exhibit this problem as there the check is compiled fine.

I am not sure if this is a bug in compiler (though it seems the behavior is there since quite some time) which is too ambitious, but there is a compiler flag, which disables this optimization even in the release build -fno-delete-null-pointer-checks (supposedly available from clang 7), but the problem is, the library client must add this flag manually when using the library code.

There seems to be the similar warning (treatment) for gcc, but I do not have a gcc environment to test, if this warning is harmless, or produces the same problem.

I guess the best solution would be rewriting the code in a way it does not fall for this optimization, but so far I did not find how or if possible at all (I am not that much familiar with clang).

It is also strange that it does not get caught by CI/CD tests.

Reproduction steps

Run the release build of test-class_parser_cpp11 unit test, built with the recent version (21.1.8) of clang (on macOS), or clang-cl.exe (on Windows).

Expected vs. actual results

Should not crash.

Minimal code example

Error messages

[doctest] doctest version is "2.4.12"
[doctest] run with "--help" for options
===============================================================================
/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/src/unit-class_parser.cpp:343:
TEST CASE:  parser class
  improve test coverage
  SAX parser
  null sax handler

/Users/risa/Work_OSS/_risa2000/nlohmann_json/tests/src/unit-class_parser.cpp:343: FATAL ERROR: test case CRASHED: SIGSEGV - Segmentation violation signal

Compiler and operating system

clang (macOS), clang-cl.exe (Windows), version 21.1.8.

Library version

develop

Validation

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions