[clang] [clang][Lex] Collapse relative extern module paths when recursing to prevent unbounded path length growth. (PR #193691)

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 23 01:51:03 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Tom Murray (TomMurray)

<details>
<summary>Changes</summary>

Ref #<!-- -->147220.

### Problem Description
Bazel's use of clang modules for its `layering_check` emits `extern module` declarations relative to some base path meaning those paths usually include long sequences of `../` followed by the path to the module itself.

When parsing `extern module` in the module file, we (I believe intentionally) silently ignore missing module files. Currently in the problem case if the file existence check failed for any _other_ reason it also silently ignores it. This means that `-fmodules-strict-decluse` that bazel uses for the layering_check can throw a spurious `err_undeclared_use_of_module` error which is the problem reported in #<!-- -->147220.

Clang's `extern module` parsing chooses to concatenate these relative paths recursively meaning the growth in those paths is unbounded. In this case the file existence check fails due to the path name being too long (ENAMETOOLONG in POSIX).

In summary there are possibly 2 underlying problems that contribute to #<!-- -->147220 that we could try to fix:
1. Silently ignoring unexpected errors (ENAMETOOLONG) meaning the ultimately reported error (undeclared use of module) doesn't really help the user understand what was wrong.
2. Unbounded path growth when recursively declaring `extern module`s in a chain.

I'm choosing to focus on (2) in this PR because both fixes seem useful, and (1) seems an intentional design choice.

### Implementation
Collapse `../` in relative `extern module` paths before loading those modules for parsing.

---
Full diff: https://github.com/llvm/llvm-project/pull/193691.diff


1 Files Affected:

- (modified) clang/lib/Lex/ModuleMap.cpp (+7) 


``````````diff
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 56ae51ada7148..a164798db5314 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -2001,6 +2001,13 @@ void ModuleMapLoader::handleExternModuleDecl(
   if (llvm::sys::path::is_relative(FileNameRef)) {
     ModuleMapFileName += Directory.getName();
     llvm::sys::path::append(ModuleMapFileName, EMD.Path);
+    // As extern module declarations are parsed recursively, relative paths
+    // to those modules can become arbitrarily long.
+    // If the OS name length limit is exceeded when trying to get the file ref
+    // we can silently fail to find an extern module that exists.
+    // To mitigate this, collapse relative paths containing '../' for when
+    // constructing the name of each module file referenced as an extern module.
+    llvm::sys::path::remove_dots(ModuleMapFileName, /*remove_dot_dot=*/true);
     FileNameRef = ModuleMapFileName;
   }
   if (auto File = SourceMgr.getFileManager().getOptionalFileRef(FileNameRef))

``````````

</details>


https://github.com/llvm/llvm-project/pull/193691


More information about the cfe-commits mailing list