[clang-doc] crashes when generating HTML without --repository flag · Issue #131697 · llvm/llvm-project (original) (raw)
Issue Description
After merging PR #122566, the clang-doc tool crashes with an assertion failure when attempting to generate HTML documentation without explicitly specifying the --repository
flag. The tool fails with:
/usr/include/c++/14.2.1/optional:475: constexpr _Tp& std::_Optional_base_impl<_Tp, _Dp>::_M_get() [with _Tp = llvm::StringRef; _Dp = std::_Optional_base<llvm::StringRef, true, true>]: Assertion 'this->_M_is_engaged()' failed.
Steps to Reproduce
- Build clang-doc from the latest source after merging PR [clang-doc] Make --repository change the HTML output #122566
- Run the tool on a C++ file with HTML output format but without the
--repository
flag:
clang-doc src/Calculator.cpp --format=html -- -I./include
Stack Trace
/usr/include/c++/14.2.1/optional:475: constexpr _Tp& std::_Optional_base_impl<_Tp, _Dp>::_M_get() [with _Tp = llvm::StringRef; _Dp = std::_Optional_base<llvm::StringRef, true, true>]: Assertion 'this->_M_is_engaged()' failed.
#0 0x00005ff1c4b6d1de llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/mohamed/dev/contrib/llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:804:22
#1 0x00005ff1c4b6d5f1 PrintStackTraceSignalHandler(void*) /home/mohamed/dev/contrib/llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:880:1
#2 0x00005ff1c4b6aa83 llvm::sys::RunSignalHandlers() /home/mohamed/dev/contrib/llvm/llvm-project/llvm/lib/Support/Signals.cpp:105:20
#3 0x00005ff1c4b6ca92 SignalHandler(int, siginfo_t*, void*) /home/mohamed/dev/contrib/llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:418:13
#4 0x000074807044bcd0 (/usr/lib/libc.so.6+0x3dcd0)
#5 0x00007480704a5624 __pthread_kill_implementation /usr/src/debug/glibc/glibc/nptl/pthread_kill.c:44:76
#6 0x000074807044bba0 raise /usr/src/debug/glibc/glibc/signal/../sysdeps/posix/raise.c:27:6
#7 0x0000748070433582 abort /usr/src/debug/glibc/glibc/stdlib/abort.c:81:3
#8 0x00007480706d3f70 std::chrono::_V2::system_clock::now() /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/chrono.cc:52:5
#9 0x00005ff1c4b20874 std::_Optional_base_impl<llvm::StringRef, std::_Optional_base<llvm::StringRef, true, true>>::_M_get() /usr/include/c++/14.2.1/optional:476:51
#10 0x00005ff1c4b1aba4 std::optional<llvm::StringRef>::operator*() & /usr/include/c++/14.2.1/optional:972:32
#11 0x00005ff1c588885f clang::doc::writeFileDefinition(clang::doc::Location const&, std::optional<llvm::StringRef>) /home/mohamed/dev/contrib/llvm/llvm-project/clang-tools-extra/clang-doc/HTMLGenerator.cpp:501:42
#12 0x00005ff1c588add0 clang::doc::genHTML(clang::doc::FunctionInfo const&, clang::doc::ClangDocContext const&, llvm::StringRef) /home/mohamed/dev/contrib/llvm/llvm-project/clang-tools-extra/clang-doc/HTMLGenerator.cpp:803:43
#13 0x00005ff1c5887dab clang::doc::genFunctionsBlock(std::vector<clang::doc::FunctionInfo, std::allocator<clang::doc::FunctionInfo>> const&, clang::doc::ClangDocContext const&, llvm::StringRef) /home/mohamed/dev/contrib/llvm/llvm-project/clang-tools-extra/clang-doc/HTMLGenerator.cpp:442:43
#14 0x00005ff1c588bcf1 clang::doc::genHTML(clang::doc::RecordInfo const&, clang::doc::Index&, clang::doc::ClangDocContext const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&) /home/mohamed/dev/contrib/llvm/llvm-project/clang-tools-extra/clang-doc/HTMLGenerator.cpp:908:25
#15 0x00005ff1c588c893 clang::doc::HTMLGenerator::generateDocForInfo(clang::doc::Info*, llvm::raw_ostream&, clang::doc::ClangDocContext const&) /home/mohamed/dev/contrib/llvm/llvm-project/clang-tools-extra/clang-doc/HTMLGenerator.cpp:1014:59
#16 0x00005ff1c588c622 clang::doc::HTMLGenerator::generateDocs(llvm::StringRef, llvm::StringMap<std::unique_ptr<clang::doc::Info, std::default_delete<clang::doc::Info>>, llvm::MallocAllocator>, clang::doc::ClangDocContext const&) /home/mohamed/dev/contrib/llvm/llvm-project/clang-tools-extra/clang-doc/HTMLGenerator.cpp:993:68
#17 0x00005ff1c4a2d2ac main /home/mohamed/dev/contrib/llvm/llvm-project/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp:371:33
#18 0x0000748070435488 __libc_start_call_main /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#19 0x000074807043554c call_init /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:128:20
#20 0x000074807043554c __libc_start_main /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:347:5
#21 0x00005ff1c4a2b225 _start (/home/mohamed/dev/contrib/llvm/llvm-project/build/bin/clang-doc+0x2e7225)
[1] 910707 IOT instruction (core dumped) ~/dev/contrib/llvm/llvm-project/build/bin/clang-doc src/Calculator.cpp --
Root Cause
The issue stems from a logical condition change in PR #122566. In the writeFileDefinition
function, the condition was changed from:
if (!L.IsFileInRootDir || !RepositoryUrl)
to:
if (!L.IsFileInRootDir && !RepositoryUrl)
This change means that when RepositoryUrl
is not provided (which happens when --repository
flag is omitted), the function proceeds to code paths that attempt to dereference the optional without first checking if it contains a value.
Solution
The fix is straightforward - revert the condition back to its original state:
static std::unique_ptr writeFileDefinition(const Location &L, std::optional RepositoryUrl = std::nullopt) {
- if (!L.IsFileInRootDir && !RepositoryUrl)
- if (!L.IsFileInRootDir || !RepositoryUrl) return std::make_unique( HTMLTag::TAG_P, "Defined at line " + std::to_string(L.LineNumber) + " of file " + L.Filename);
This change ensures that if RepositoryUrl is not provided, the function takes a safe path that doesn't attempt to dereference the empty optional.