llvm / llvm/llvm-project

[clangd][modules] Assertion `CurrentModuleMapEntry && "module map file entry not found"' failed.

Open
#205,598 2 comments 0 reactions 0 assignees View on GitHub
clang:modules clangd crash
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

It creates a tiny repro workspace with four files:

- main.cpp: includes a.h twice
- a.h: defines FOO
- module.modulemap: declares a module for a.h
- compile_commands.json: tells clangd to parse main.cpp with -fmodules, -fmodule-map-file=module.modulemap, and the Windows target

reproducer:

```
python reproducer.py /path/to/clangd
```

```python
#!/usr/bin/env python3
import argparse
import json
import os
import shutil
import subprocess
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[3]
DEFAULT_BIN = ROOT / "tmp/build-assert-clangd-main-20260623-latest/bin"
SCRIPT_DIR = Path(__file__).resolve().parent
WORK = SCRIPT_DIR / "repro_workspace"

FILES = {
"main.cpp": """#include "./a.h"
#include "./a.h" // duplicate

#ifndef FOO
#error foo
#endif
""",
"a.h": """#define FOO
""",
"module.modulemap": None,
}

def tool_path(name: str) -> str:
env_name = name.upper().replace("+", "X") + "_BIN"
return os.environ.get(env_name, str(DEFAULT_BIN / name))

def resolve_tool_path(raw: str) -> str:
p = Path(raw)
if p.is_absolute():
return str(p)
for base in (Path.cwd(), SCRIPT_DIR, ROOT):
candidate = (base / p).resolve()
if candidate.exists():
return str(candidate)
return str(p.resolve())

def write_workspace(clangxx: str) -> None:
if WORK.exists():
shutil.rmtree(WORK)
WORK.mkdir(parents=True)

for rel, content in FILES.items():
if rel == "module.modulemap":
content = f'module a {{\n header "{WORK / "a.h"}"\n}}\n'
(WORK / rel).write_text(content, encoding="utf-8")

compile_commands = [
{
"directory": str(WORK),
"file": str(WORK / "main.cpp"),
"command": " ".join(
[
clangxx,
"-std=c++20",
"-fsyntax-only",
"-fmodules",
"-fmodule-map-file=module.modulemap",
"-I.",
"--target=x86_64-pc-win32",
"main.cpp",
]
),
}
]
(WORK / "compile_commands.json").write_text(
json.dumps(compile_commands, indent=2) + "\n", encoding="utf-8"
)

def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--clangd", default=tool_path("clangd"))
parser.add_argument("--clangxx", default=tool_path("clang++"))
args = parser.parse_args()

clangd = resolve_tool_path(args.clangd)
clangxx = resolve_tool_path(args.clangxx)
write_workspace(clangxx)

argv = [
clangd,
f"--check={WORK / 'main.cpp'}",
"--compile-commands-dir=.",
"--background-index=false",
"--experimental-modules-support",
]
print("+", " ".join(argv), flush=True)
proc = subprocess.run(argv, cwd=WORK, check=False)
return proc.returncode

if __name__ == "__main__":
raise SystemExit(main())
```

stacktrace:
```
#0 0x000059f5243066b2 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /tmp/llvm-project-main-20260622-latest/llvm/lib/Support/Unix/Signals.inc:885:3
#1 0x000059f5243034fc llvm::sys::RunSignalHandlers() /tmp/llvm-project-main-20260622-latest/llvm/lib/Support/Signals.cpp:108:20
#2 0x000059f524303d71 SignalHandler(int, siginfo_t*, void*) /tmp/llvm-project-main-20260622-latest/llvm/lib/Support/Unix/Signals.inc:448:14
#3 0x00007fe1b0a45330 (/lib/x86_64-linux-gnu/libc.so.6+0x45330)
#4 0x00007fe1b0a9eb2c __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
#5 0x00007fe1b0a9eb2c __pthread_kill_internal ./nptl/pthread_kill.c:78:10
#6 0x00007fe1b0a9eb2c pthread_kill ./nptl/pthread_kill.c:89:10
#7 0x00007fe1b0a4527e raise ./signal/../sysdeps/posix/raise.c:27:6
#8 0x00007fe1b0a288ff abort ./stdlib/abort.c:81:7
#9 0x00007fe1b0a2881b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x00007fe1b0a3b517 (/lib/x86_64-linux-gnu/libc.so.6+0x3b517)
#11 0x000059f52697ffa6 clang::dependencies::ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs(clang::dependencies::ModuleDeps const&, llvm::function_ref) const /tmp/llvm-project-main-20260622-latest/clang/lib/DependencyScanning/ModuleDepCollector.cpp:317:3
#12 0x000059f526982968 clang::dependencies::ModuleDepCollector::handleTopLevelModule(clang::serialization::ModuleFile*) /tmp/llvm-project-main-20260622-latest/clang/lib/DependencyScanning/ModuleDepCollector.cpp:816:13
#13 0x000059f526983297 std::_Optional_payload_base::_M_reset() /usr/include/c++/13/optional:317:2
#14 0x000059f526983297 std::_Optional_payload::~_Optional_payload() /usr/include/c++/13/optional:441:65
#15 0x000059f526983297 std::_Optional_base::~_Optional_base() /usr/include/c++/13/optional:512:12
#16 0x000059f526983297 std::optional::~optional() /usr/include/c++/13/optional:707:11
#17 0x000059f526983297 clang::dependencies::ModuleDepCollector::run(clang::dependencies::DependencyConsumer&) /tmp/llvm-project-main-20260622-latest/clang/lib/DependencyScanning/ModuleDepCollector.cpp:665:25
#18 0x000059f526974d79 std::__uniq_ptr_impl>::_M_ptr() const /usr/include/c++/13/bits/unique_ptr.h:199:67
#19 0x000059f526974d79 std::unique_ptr>::get() const /usr/include/c++/13/bits/unique_ptr.h:470:27
#20 0x000059f526974d79 std::unique_ptr>::operator*() const /usr/include/c++/13/bits/unique_ptr.h:453:2
#21 0x000059f526974d79 clang::dependencies::DependencyScanningAction::runInvocation(std::__cxx11::basic_string, std::allocator>, std::unique_ptr>, llvm::IntrusiveRefCntPtr, std::shared_ptr, clang::DiagnosticConsumer*) /tmp/llvm-project-main-20260622-latest/clang/lib/DependencyScanning/DependencyScannerImpl.cpp:791:41
#22 0x000059f5269651db std::__cxx11::basic_string, std::allocator>::_M_data() const /usr/include/c++/13/bits/basic_string.h:223:28
#23 0x000059f5269651db std::__cxx11::basic_string, std::allocator>::_M_is_local() const /usr/include/c++/13/bits/basic_string.h:264:13
#24 0x000059f5269651db std::__cxx11::basic_string, std::allocator>::_M_dispose() /usr/include/c++/13/bits/basic_string.h:282:18
#25 0x000059f5269651db std::__cxx11::basic_string, std::allocator>::~basic_string() /usr/include/c++/13/bits/basic_string.h:804:19
#26 0x000059f5269651db createAndRunToolInvocation /tmp/llvm-project-main-20260622-latest/clang/lib/DependencyScanning/DependencyScanningWorker.cpp:54:30
#27 0x000059f5269651db auto clang::dependencies::DependencyScanningWorker::computeDependencies(llvm::StringRef, llvm::ArrayRef, std::allocator>>>, clang::dependencies::DependencyConsumer&, clang::dependencies::DependencyActionController&, clang::DiagnosticConsumer&, llvm::IntrusiveRefCntPtr)::'lambda'(auto const&)::operator(), std::allocator>>>(auto const&) const /tmp/llvm-project-main-20260622-latest/clang/lib/DependencyScanning/DependencyScanningWorker.cpp:99:38
#28 0x000059f526967137 __find_if >*, __gnu_cxx::__ops::_Iter_negate > >, clang::dependencies::DependencyConsumer&, clang::dependencies::DependencyActionController&, clang::DiagnosticConsumer&, llvm::IntrusiveRefCntPtr):: > > /usr/include/c++/13/bits/stl_algobase.h:2102:4
#29 0x000059f526967137 __find_if_not >*, __gnu_cxx::__ops::_Iter_pred > >, clang::dependencies::DependencyConsumer&, clang::dependencies::DependencyActionController&, clang::DiagnosticConsumer&, llvm::IntrusiveRefCntPtr):: > > /usr/include/c++/13/bits/stl_algo.h:112:28
#30 0x000059f526967137 find_if_not >*, clang::dependencies::DependencyScanningWorker::computeDependencies(llvm::StringRef, llvm::ArrayRef > >, clang::dependencies::DependencyConsumer&, clang::dependencies::DependencyActionController&, clang::DiagnosticConsumer&, llvm::IntrusiveRefCntPtr):: > /usr/include/c++/13/bits/stl_algo.h:519:32
#31 0x000059f526967137 all_of >*, clang::dependencies::DependencyScanningWorker::computeDependencies(llvm::StringRef, llvm::ArrayRef > >, clang::dependencies::DependencyConsumer&, clang::dependencies::DependencyActionController&, clang::DiagnosticConsumer&, llvm::IntrusiveRefCntPtr):: > /usr/include/c++/13/bits/stl_algo.h:459:40
#32 0x000059f526967137 all_of > >&, clang::dependencies::DependencyScanningWorker::computeDependencies(llvm::StringRef, llvm::ArrayRef > >, clang::dependencies::DependencyConsumer&, clang::dependencies::DependencyActionController&, clang::DiagnosticConsumer&, llvm::IntrusiveRefCntPtr):: > /tmp/llvm-project-main-20260622-latest/llvm/include/llvm/ADT/STLExtras.h:1739:21
#33 0x000059f526967137 clang::dependencies::DependencyScanningWorker::computeDependencies(llvm::StringRef, llvm::ArrayRef, std::allocator>>>, clang::dependencies::DependencyConsumer&, clang::dependencies::DependencyActionController&, clang::DiagnosticConsumer&, llvm::IntrusiveRefCntPtr) /tmp/llvm-project-main-20260622-latest/clang/lib/DependencyScanning/DependencyScanningWorker.cpp:84:36
#34 0x000059f5267028cc computeDependenciesForDriverCommandLine(clang::dependencies::DependencyScanningWorker&, llvm::StringRef, llvm::ArrayRef, std::allocator>>, clang::dependencies::DependencyConsumer&, clang::dependencies::DependencyActionController&, clang::DiagnosticConsumer&, llvm::IntrusiveRefCntPtr) /tmp/llvm-project-main-20260622-latest/clang/lib/Tooling/DependencyScanningTool.cpp:169:36
#35 0x000059f526702d8b llvm::IntrusiveRefCntPtr::release() /tmp/llvm-project-main-20260622-latest/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h:232:9
#36 0x000059f526702d8b llvm::IntrusiveRefCntPtr::~IntrusiveRefCntPtr() /tmp/llvm-project-main-20260622-latest/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h:196:34
#37 0x000059f526702d8b clang::tooling::computeDependencies(clang::dependencies::DependencyScanningWorker&, llvm::StringRef, llvm::ArrayRef, std::allocator>>, clang::dependencies::DependencyConsumer&, clang::dependencies::DependencyActionController&, clang::DiagnosticConsumer&, llvm::IntrusiveRefCntPtr) /tmp/llvm-project-main-20260622-latest/clang/lib/Tooling/DependencyScanningTool.cpp:189:62
#38 0x000059f526702f73 clang::tooling::DependencyScanningTool::getP1689ModuleDependencyFile(clang::tooling::CompileCommand const&, llvm::StringRef, std::__cxx11::basic_string, std::allocator>&, std::__cxx11::basic_string, std::allocator>&, clang::DiagnosticConsumer&) /tmp/llvm-project-main-20260622-latest/clang/lib/Tooling/DependencyScanningTool.cpp:256:3
#39 0x000059f525951010 std::__cxx11::basic_string, std::allocator>::_M_data() const /usr/include/c++/13/bits/basic_string.h:223:28
#40 0x000059f525951010 std::__cxx11::basic_string, std::allocator>::_M_is_local() const /usr/include/c++/13/bits/basic_string.h:264:13
#41 0x000059f525951010 std::__cxx11::basic_string, std::allocator>::_M_dispose() /usr/include/c++/13/bits/basic_string.h:282:18
#42 0x000059f525951010 std::__cxx11::basic_string, std::allocator>::~basic_string() /usr/include/c++/13/bits/basic_string.h:804:19
#43 0x000059f525951010 clang::tooling::DependencyScanningTool::getP1689ModuleDependencyFile(clang::tooling::CompileCommand const&, llvm::StringRef, clang::DiagnosticConsumer&) /tmp/llvm-project-main-20260622-latest/clang/include/clang/Tooling/DependencyScanningTool.h:77:3
#44 0x000059f525951010 clang::clangd::(anonymous namespace)::ModuleDependencyScanner::scan(llvm::StringRef, llvm::unique_function const&) /tmp/llvm-project-main-20260622-latest/clang-tools-extra/clangd/ProjectModules.cpp:231:61
#45 0x000059f525952539 clang::clangd::(anonymous namespace)::ModuleDependencyScanner::getRequiredModules(llvm::StringRef, llvm::unique_function const&) /tmp/llvm-project-main-20260622-latest/clang-tools-extra/clangd/ProjectModules.cpp:292:3
#46 0x000059f5259527cb clang::clangd::CompoundProjectModules::getRequiredModules[abi:cxx11](llvm::StringRef) /tmp/llvm-project-main-20260622-latest/clang-tools-extra/clangd/ProjectModules.cpp:540:3
#47 0x000059f525942c58 getRequiredModules /tmp/llvm-project-main-20260622-latest/clang-tools-extra/clangd/ModulesBuilder.cpp:865:40
#48 0x000059f525942c58 clang::clangd::ModulesBuilder::buildPrerequisiteModulesFor(llvm::StringRef, clang::clangd::ThreadsafeFS const&) /tmp/llvm-project-main-20260622-latest/clang-tools-extra/clangd/ModulesBuilder.cpp:1243:40
#49 0x000059f5259a20ae std::__uniq_ptr_impl>::reset(clang::clangd::PrerequisiteModules*) /usr/include/c++/13/bits/unique_ptr.h:208:16
#50 0x000059f5259a20ae std::__uniq_ptr_impl>::operator=(std::__uniq_ptr_impl>&&) /usr/include/c++/13/bits/unique_ptr.h:191:7
#51 0x000059f5259a20ae std::__uniq_ptr_data, true, true>::operator=(std::__uniq_ptr_data, true, true>&&) /usr/include/c++/13/bits/unique_ptr.h:243:24
#52 0x000059f5259a20ae std::unique_ptr>::operator=(std::unique_ptr>&&) /usr/include/c++/13/bits/unique_ptr.h:414:19
#53 0x000059f5259a20ae clang::clangd::buildPreamble(llvm::StringRef, clang::CompilerInvocation, clang::clangd::ParseInputs const&, bool, std::function)>, clang::clangd::PreambleBuildStats*) /tmp/llvm-project-main-20260622-latest/clang-tools-extra/clangd/Preamble.cpp:681:73
#54 0x000059f52571839b std::__shared_count<(__gnu_cxx::_Lock_policy)2>::_M_swap(std::__shared_count<(__gnu_cxx::_Lock_policy)2>&) /usr/include/c++/13/bits/shared_ptr_base.h:1099:25
#55 0x000059f52571839b std::__shared_ptr::swap(std::__shared_ptr&) /usr/include/c++/13/bits/shared_ptr_base.h:1687:21
#56 0x000059f52571839b std::__shared_ptr::operator=(std::__shared_ptr&&) /usr/include/c++/13/bits/shared_ptr_base.h:1620:35
#57 0x000059f52571839b std::shared_ptr::operator=(std::shared_ptr&&) /usr/include/c++/13/bits/shared_ptr.h:440:36
#58 0x000059f52571839b buildAST /tmp/llvm-project-main-20260622-latest/clang-tools-extra/clangd/tool/Check.cpp:257:10
#59 0x000059f52571839b clang::clangd::check(llvm::StringRef, clang::clangd::ThreadsafeFS const&, clang::clangd::ClangdLSPServer::Options const&) /tmp/llvm-project-main-20260622-latest/clang-tools-extra/clangd/tool/Check.cpp:525:18
#60 0x000059f52570dd1a clang::clangd::clangdMain(int, char**) /tmp/llvm-project-main-20260622-latest/clang-tools-extra/clangd/tool/ClangdMain.cpp:1059:16
#61 0x00007fe1b0a2a1ca __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#62 0x00007fe1b0a2a28b call_init ./csu/../csu/libc-start.c:128:20
#63 0x00007fe1b0a2a28b __libc_start_main ./csu/../csu/libc-start.c:347:5
#64 0x000059f5241efba5 _start (/tmp/build-assert-clangd-main-20260623-latest/bin/clangd+0x3e5ba5)
```

Contributor guide

Open the contributing guide

Research direction

Start by running reproducer.py with clangd and clang++, then inspect clang/lib/DependencyScanning/ModuleDepCollector.cpp at the assertion near line 317 and its caller handleTopLevelModule near line 816. Confirm the four-file modules workspace no longer aborts when main.cpp includes a.h twice; preserve the reported module-dependency behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.