Skip to content

Commit a417fa0

Browse files
committed
[Modules] Do not remove failed modules after the control block phase
Reading modules first reads each control block in the chain and then all AST blocks. The first phase is intended to find recoverable errors, eg. an out of date or missing module. If any error occurs during this phase, it is safe to remove all modules in the chain as no references to them will exist. While reading the AST blocks, however, various fields in ASTReader are updated with references to the module. Removing modules at this point can cause dangling pointers which can be accessed later. These would be otherwise harmless, eg. a binary search over `GlobalSLocEntryMap` may access a failed module that could error, but shouldn't crash. Do not remove modules in this phase, regardless of failures. Since this is the case, it also doesn't make sense to return OutOfDate during this phase, so remove the two cases where this happens. When they were originally added these checks would return a failure when the serialized and current path didn't match up. That was updated to an OutOfDate as it was found to be hit when using VFS and overriding the umbrella. Later on the path was changed to instead be the name as written in the module file, resolved using the serialized base directory. At this point the check is really only comparing the name of the umbrella and only works for frameworks since those don't include `Headers/` in the name (which means the resolved path will never exist) Given all that, it seems safe to ignore this case entirely for now. This makes the handling of an umbrella header/directory the same as regular headers, which also don't check for differences in the path caused by VFS. Resolves rdar://79329355 Differential Revision: https://reviews.llvm.org/D107690
1 parent a53e20d commit a417fa0

File tree

5 files changed

+104
-43
lines changed

5 files changed

+104
-43
lines changed

clang/lib/Serialization/ASTReader.cpp

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4214,8 +4214,11 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
42144214
PreviousGeneration = incrementGeneration(*ContextObj);
42154215

42164216
unsigned NumModules = ModuleMgr.size();
4217-
auto removeModulesAndReturn = [&](ASTReadResult ReadResult) {
4218-
assert(ReadResult && "expected to return error");
4217+
SmallVector<ImportedModule, 4> Loaded;
4218+
if (ASTReadResult ReadResult =
4219+
ReadASTCore(FileName, Type, ImportLoc,
4220+
/*ImportedBy=*/nullptr, Loaded, 0, 0, ASTFileSignature(),
4221+
ClientLoadCapabilities)) {
42194222
ModuleMgr.removeModules(ModuleMgr.begin() + NumModules,
42204223
PP.getLangOpts().Modules
42214224
? &PP.getHeaderSearchInfo().getModuleMap()
@@ -4226,22 +4229,6 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
42264229
GlobalIndex.reset();
42274230
ModuleMgr.setGlobalIndex(nullptr);
42284231
return ReadResult;
4229-
};
4230-
4231-
SmallVector<ImportedModule, 4> Loaded;
4232-
switch (ASTReadResult ReadResult =
4233-
ReadASTCore(FileName, Type, ImportLoc,
4234-
/*ImportedBy=*/nullptr, Loaded, 0, 0,
4235-
ASTFileSignature(), ClientLoadCapabilities)) {
4236-
case Failure:
4237-
case Missing:
4238-
case OutOfDate:
4239-
case VersionMismatch:
4240-
case ConfigurationMismatch:
4241-
case HadErrors:
4242-
return removeModulesAndReturn(ReadResult);
4243-
case Success:
4244-
break;
42454232
}
42464233

42474234
// Here comes stuff that we only do once the entire chain is loaded.
@@ -4253,18 +4240,18 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
42534240

42544241
// Read the AST block.
42554242
if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities))
4256-
return removeModulesAndReturn(Result);
4243+
return Failure;
42574244

42584245
// The AST block should always have a definition for the main module.
42594246
if (F.isModule() && !F.DidReadTopLevelSubmodule) {
42604247
Error(diag::err_module_file_missing_top_level_submodule, F.FileName);
4261-
return removeModulesAndReturn(Failure);
4248+
return Failure;
42624249
}
42634250

42644251
// Read the extension blocks.
42654252
while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) {
42664253
if (ASTReadResult Result = ReadExtensionBlock(F))
4267-
return removeModulesAndReturn(Result);
4254+
return Failure;
42684255
}
42694256

42704257
// Once read, set the ModuleFile bit base offset and update the size in
@@ -5612,17 +5599,20 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
56125599
}
56135600

56145601
case SUBMODULE_UMBRELLA_HEADER: {
5602+
// FIXME: This doesn't work for framework modules as `Filename` is the
5603+
// name as written in the module file and does not include
5604+
// `Headers/`, so this path will never exist.
56155605
std::string Filename = std::string(Blob);
56165606
ResolveImportedPath(F, Filename);
56175607
if (auto Umbrella = PP.getFileManager().getFile(Filename)) {
5618-
if (!CurrentModule->getUmbrellaHeader())
5608+
if (!CurrentModule->getUmbrellaHeader()) {
56195609
// FIXME: NameAsWritten
56205610
ModMap.setUmbrellaHeader(CurrentModule, *Umbrella, Blob, "");
5621-
else if (CurrentModule->getUmbrellaHeader().Entry != *Umbrella) {
5622-
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
5623-
Error("mismatched umbrella headers in submodule");
5624-
return OutOfDate;
56255611
}
5612+
// Note that it's too late at this point to return out of date if the
5613+
// name from the PCM doesn't match up with the one in the module map,
5614+
// but also quite unlikely since we will have already checked the
5615+
// modification time and size of the module map file itself.
56265616
}
56275617
break;
56285618
}
@@ -5646,16 +5636,13 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
56465636
break;
56475637

56485638
case SUBMODULE_UMBRELLA_DIR: {
5639+
// See comments in SUBMODULE_UMBRELLA_HEADER
56495640
std::string Dirname = std::string(Blob);
56505641
ResolveImportedPath(F, Dirname);
56515642
if (auto Umbrella = PP.getFileManager().getDirectory(Dirname)) {
5652-
if (!CurrentModule->getUmbrellaDir())
5643+
if (!CurrentModule->getUmbrellaDir()) {
56535644
// FIXME: NameAsWritten
56545645
ModMap.setUmbrellaDir(CurrentModule, *Umbrella, Blob, "");
5655-
else if (CurrentModule->getUmbrellaDir().Entry != *Umbrella) {
5656-
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
5657-
Error("mismatched umbrella directories in submodule");
5658-
return OutOfDate;
56595646
}
56605647
}
56615648
break;

clang/test/VFS/Inputs/UsesFoo.framework/Headers/UsesFoo.h

Lines changed: 0 additions & 1 deletion
This file was deleted.

clang/test/VFS/Inputs/UsesFoo.framework/Modules/module.modulemap

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: sed -e "s;TEST_DIR;%/t;g" %t/sed-overlay.yaml > %t/overlay.yaml
4+
5+
// These tests first build with an overlay such that the header is resolved
6+
// to %t/other/Mismatch.h. They then build again with the header resolved
7+
// to the one in their directory.
8+
//
9+
// This should cause a rebuild if the contents is different (and thus multiple
10+
// PCMs), but this currently isn't the case. We should at least not error,
11+
// since this does happen in real projects (with a different copy of the same
12+
// file).
13+
14+
// RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/hf-mcp -ivfsoverlay %t/overlay.yaml -F %t/header-frameworks -fsyntax-only -verify %t/use.m
15+
// RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/hf-mcp -F %t/header-frameworks -fsyntax-only -verify %t/use.m
16+
// RUN: find %t/hf-mcp -name "Mismatch-*.pcm" | count 1
17+
18+
// RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/df-mcp -ivfsoverlay %t/overlay.yaml -F %t/dir-frameworks -fsyntax-only -verify %t/use.m
19+
// RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/hf-mcp -F %t/dir-frameworks -fsyntax-only -verify %t/use.m
20+
// RUN: find %t/df-mcp -name "Mismatch-*.pcm" | count 1
21+
22+
// RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/nf-mcp -ivfsoverlay %t/overlay.yaml -F %t/norm-frameworks -fsyntax-only -verify %t/use.m
23+
// RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/nf-mcp -F %t/norm-frameworks -fsyntax-only -verify %t/use.m
24+
// RUN: find %t/nf-mcp -name "Mismatch-*.pcm" | count 1
25+
26+
// RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/m-mcp -ivfsoverlay %t/overlay.yaml -I %t/mod -fsyntax-only -verify %t/use.m
27+
// RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/m-mcp -I %t/mod -fsyntax-only -verify %t/use.m
28+
// RUN: find %t/m-mcp -name "Mismatch-*.pcm" | count 1
29+
30+
//--- use.m
31+
// expected-no-diagnostics
32+
@import Mismatch;
33+
34+
//--- header-frameworks/Mismatch.framework/Modules/module.modulemap
35+
framework module Mismatch {
36+
umbrella header "Mismatch.h"
37+
}
38+
//--- header-frameworks/Mismatch.framework/Headers/Mismatch.h
39+
40+
//--- dir-frameworks/Mismatch.framework/Modules/module.modulemap
41+
framework module Mismatch {
42+
umbrella "someheaders"
43+
}
44+
//--- dir-frameworks/Mismatch.framework/someheaders/Mismatch.h
45+
46+
//--- norm-frameworks/Mismatch.framework/Modules/module.modulemap
47+
framework module Mismatch {
48+
header "Mismatch.h"
49+
}
50+
//--- norm-frameworks/Mismatch.framework/Headers/Mismatch.h
51+
52+
//--- mod/module.modulemap
53+
module Mismatch {
54+
umbrella header "Mismatch.h"
55+
}
56+
//--- mod/Mismatch.h
57+
58+
//--- other/Mismatch.h
59+
60+
//--- sed-overlay.yaml
61+
{
62+
'version': 0,
63+
'roots': [
64+
{ 'name': 'TEST_DIR', 'type': 'directory',
65+
'contents': [
66+
{ 'name': 'header-frameworks/Mismatch.framework/Headers/Mismatch.h',
67+
'type': 'file',
68+
'external-contents': 'TEST_DIR/other/Mismatch.h'
69+
},
70+
{ 'name': 'dir-frameworks/Mismatch.framework/someheaders',
71+
'type': 'directory',
72+
'external-contents': 'TEST_DIR/others'
73+
},
74+
{ 'name': 'norm-frameworks/Mismatch.framework/Headers/Mismatch.h',
75+
'type': 'file',
76+
'external-contents': 'TEST_DIR/other/Mismatch.h'
77+
},
78+
{ 'name': 'mod/Mismatch.h',
79+
'type': 'file',
80+
'external-contents': 'TEST_DIR/other/Mismatch.h'
81+
}
82+
]
83+
}
84+
]
85+
}
86+

clang/test/VFS/umbrella-mismatch.m

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)