From: Argyrios Kyrtzidis Date: Thu, 19 Feb 2015 20:12:20 +0000 (+0000) Subject: [PCH/Modules] Check that the specific module cache path the PCH was built with, is... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=699179bb08ba53e9fc049e7d56d4d89ce58499f1;p=clang [PCH/Modules] Check that the specific module cache path the PCH was built with, is the same as the one in the current compiler invocation. If they differ reject the PCH. This protects against the badness occurring from getting modules loaded from different module caches (see crashes). rdar://19889860 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@229909 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td index fe5fd00d73..f28f9983d0 100644 --- a/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/include/clang/Basic/DiagnosticSerializationKinds.td @@ -41,6 +41,8 @@ def err_pch_langopt_value_mismatch : Error< "%0 differs in PCH file vs. current file">; def err_pch_diagopt_mismatch : Error<"%0 is currently enabled, but was not in " "the PCH file">; +def err_pch_modulecache_mismatch : Error<"PCH was compiled with module cache " + "path '%0', but the path is currently '%1'">; def err_pch_version_too_old : Error< "PCH file uses an older PCH format that is no longer supported">; diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index f40e115c23..cee87b0475 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -575,6 +575,8 @@ public: /// and replace any existing one with it. void createPreprocessor(TranslationUnitKind TUKind); + std::string getSpecificModuleCachePath(); + /// Create the AST context. void createASTContext(); diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index d7ecf26606..27af9995aa 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -153,6 +153,7 @@ public: /// \returns true to indicate the header search options are invalid, or false /// otherwise. virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, bool Complain) { return false; } @@ -230,6 +231,7 @@ public: bool Complain) override; bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, bool Complain) override; bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain, @@ -261,6 +263,9 @@ public: bool Complain) override; bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain, std::string &SuggestedPredefines) override; + bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, + bool Complain) override; void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override; private: @@ -1496,7 +1501,8 @@ public: FileManager &FileMgr, const LangOptions &LangOpts, const TargetOptions &TargetOpts, - const PreprocessorOptions &PPOpts); + const PreprocessorOptions &PPOpts, + std::string ExistingModuleCachePath); /// \brief Returns the suggested contents of the predefines buffer, /// which contains a (typically-empty) subset of the predefines diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 187e2b78b8..5d554b717b 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -329,14 +329,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { PP->setPreprocessedOutput(getPreprocessorOutputOpts().ShowCPP); - // Set up the module path, including the hash for the - // module-creation options. - SmallString<256> SpecificModuleCache( - getHeaderSearchOpts().ModuleCachePath); - if (!getHeaderSearchOpts().DisableModuleHash) - llvm::sys::path::append(SpecificModuleCache, - getInvocation().getModuleHash()); - PP->getHeaderSearchInfo().setModuleCachePath(SpecificModuleCache); + PP->getHeaderSearchInfo().setModuleCachePath(getSpecificModuleCachePath()); // Handle generating dependencies, if requested. const DependencyOutputOptions &DepOpts = getDependencyOutputOpts(); @@ -373,6 +366,17 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { } } +std::string CompilerInstance::getSpecificModuleCachePath() { + // Set up the module path, including the hash for the + // module-creation options. + SmallString<256> SpecificModuleCache( + getHeaderSearchOpts().ModuleCachePath); + if (!getHeaderSearchOpts().DisableModuleHash) + llvm::sys::path::append(SpecificModuleCache, + getInvocation().getModuleHash()); + return SpecificModuleCache.str(); +} + // ASTContext void CompilerInstance::createASTContext() { diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 0bb5d87407..75670d9a20 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -262,6 +262,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, FileManager &FileMgr = CI.getFileManager(); PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); StringRef PCHInclude = PPOpts.ImplicitPCHInclude; + std::string SpecificModuleCachePath = CI.getSpecificModuleCachePath(); if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) { std::error_code EC; SmallString<128> DirNative; @@ -273,7 +274,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr, CI.getLangOpts(), CI.getTargetOpts(), - CI.getPreprocessorOpts())) { + CI.getPreprocessorOpts(), + SpecificModuleCachePath)) { PPOpts.ImplicitPCHInclude = Dir->path(); Found = true; break; diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index e7ecb2952a..c8673e50a0 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -501,9 +501,11 @@ namespace { } bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, bool Complain) override { Out.indent(2) << "Header search options:\n"; Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n"; + Out.indent(4) << "Module Cache: '" << SpecificModuleCachePath << "'\n"; DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes, "Use builtin include directories [-nobuiltininc]"); DUMP_BOOLEAN(HSOpts.UseStandardSystemIncludes, diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 3125b8e43e..7774b7b1c6 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -108,9 +108,12 @@ ChainedASTReaderListener::ReadFileSystemOptions(const FileSystemOptions &FSOpts, } bool ChainedASTReaderListener::ReadHeaderSearchOptions( - const HeaderSearchOptions &HSOpts, bool Complain) { - return First->ReadHeaderSearchOptions(HSOpts, Complain) || - Second->ReadHeaderSearchOptions(HSOpts, Complain); + const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, + bool Complain) { + return First->ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath, + Complain) || + Second->ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath, + Complain); } bool ChainedASTReaderListener::ReadPreprocessorOptions( const PreprocessorOptions &PPOpts, bool Complain, @@ -464,7 +467,7 @@ collectMacroDefinitions(const PreprocessorOptions &PPOpts, Macros[MacroName] = std::make_pair(MacroBody, false); } } - + /// \brief Check the preprocessor options deserialized from the control block /// against the preprocessor options in an existing preprocessor. /// @@ -591,6 +594,36 @@ bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, PP.getLangOpts()); } +/// Check the header search options deserialized from the control block +/// against the header search options in an existing preprocessor. +/// +/// \param Diags If non-null, produce diagnostics for any mismatches incurred. +static bool checkHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, + StringRef ExistingModuleCachePath, + DiagnosticsEngine *Diags, + const LangOptions &LangOpts) { + if (LangOpts.Modules) { + if (SpecificModuleCachePath != ExistingModuleCachePath) { + if (Diags) + Diags->Report(diag::err_pch_modulecache_mismatch) + << SpecificModuleCachePath << ExistingModuleCachePath; + return true; + } + } + + return false; +} + +bool PCHValidator::ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, + bool Complain) { + return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath, + PP.getHeaderSearchInfo().getModuleCachePath(), + Complain ? &Reader.Diags : nullptr, + PP.getLangOpts()); +} + void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) { PP.setCounterValue(Value); } @@ -4191,16 +4224,19 @@ namespace { const LangOptions &ExistingLangOpts; const TargetOptions &ExistingTargetOpts; const PreprocessorOptions &ExistingPPOpts; + std::string ExistingModuleCachePath; FileManager &FileMgr; - + public: SimplePCHValidator(const LangOptions &ExistingLangOpts, const TargetOptions &ExistingTargetOpts, const PreprocessorOptions &ExistingPPOpts, + StringRef ExistingModuleCachePath, FileManager &FileMgr) : ExistingLangOpts(ExistingLangOpts), ExistingTargetOpts(ExistingTargetOpts), ExistingPPOpts(ExistingPPOpts), + ExistingModuleCachePath(ExistingModuleCachePath), FileMgr(FileMgr) { } @@ -4214,6 +4250,13 @@ namespace { bool Complain) override { return checkTargetOptions(ExistingTargetOpts, TargetOpts, nullptr); } + bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + StringRef SpecificModuleCachePath, + bool Complain) override { + return checkHeaderSearchOptions(HSOpts, SpecificModuleCachePath, + ExistingModuleCachePath, + nullptr, ExistingLangOpts); + } bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain, std::string &SuggestedPredefines) override { @@ -4408,8 +4451,10 @@ bool ASTReader::isAcceptableASTFile(StringRef Filename, FileManager &FileMgr, const LangOptions &LangOpts, const TargetOptions &TargetOpts, - const PreprocessorOptions &PPOpts) { - SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, FileMgr); + const PreprocessorOptions &PPOpts, + std::string ExistingModuleCachePath) { + SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, + ExistingModuleCachePath, FileMgr); return !readASTFileControlBlock(Filename, FileMgr, validator); } @@ -4780,8 +4825,10 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record, HSOpts.UseStandardSystemIncludes = Record[Idx++]; HSOpts.UseStandardCXXIncludes = Record[Idx++]; HSOpts.UseLibcxx = Record[Idx++]; + std::string SpecificModuleCachePath = ReadString(Record, Idx); - return Listener.ReadHeaderSearchOptions(HSOpts, Complain); + return Listener.ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath, + Complain); } bool ASTReader::ParsePreprocessorOptions(const RecordData &Record, diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index ee1b631f1e..c0ce5f8e5c 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1344,6 +1344,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Record.push_back(HSOpts.UseStandardSystemIncludes); Record.push_back(HSOpts.UseStandardCXXIncludes); Record.push_back(HSOpts.UseLibcxx); + // Write out the specific module cache path that contains the module files. + AddString(PP.getHeaderSearchInfo().getModuleCachePath(), Record); Stream.EmitRecord(HEADER_SEARCH_OPTIONS, Record); // Preprocessor options. diff --git a/test/Modules/ignored_macros.m b/test/Modules/ignored_macros.m index e8ee50ace3..669db4ddc2 100644 --- a/test/Modules/ignored_macros.m +++ b/test/Modules/ignored_macros.m @@ -10,7 +10,7 @@ // RUN: %clang_cc1 -fmodules-cache-path=%t.modules -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify // RUN: not %clang_cc1 -fmodules-cache-path=%t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch %s > %t.err 2>&1 // RUN: FileCheck -check-prefix=CHECK-CONFLICT %s < %t.err -// CHECK-CONFLICT: module 'ignored_macros' found in both +// CHECK-CONFLICT: PCH was compiled with module cache path // Third trial: pass -DIGNORED=1 only to the second invocation, but // make it ignored. There should be no failure, IGNORED is defined in diff --git a/test/Modules/implementation-of-module.m b/test/Modules/implementation-of-module.m index b398404201..818cce8c36 100644 --- a/test/Modules/implementation-of-module.m +++ b/test/Modules/implementation-of-module.m @@ -16,7 +16,7 @@ // RUN: %clang_cc1 -x objective-c-header -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \ // RUN: -fmodule-implementation-of category_right -emit-pch -o %t.pch // RUN: %clang_cc1 -x objective-c-header -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \ -// RUN: -DWITH_PREFIX -include-pch %t.pch -fmodule-implementation-of category_right +// RUN: -DWITH_PREFIX -fmodules-ignore-macro=WITH_PREFIX -include-pch %t.pch -fmodule-implementation-of category_right #ifndef WITH_PREFIX diff --git a/test/PCH/Inputs/modules/Foo.h b/test/PCH/Inputs/modules/Foo.h new file mode 100644 index 0000000000..d661dbccbc --- /dev/null +++ b/test/PCH/Inputs/modules/Foo.h @@ -0,0 +1 @@ +void make_foo(void); diff --git a/test/PCH/Inputs/modules/module.modulemap b/test/PCH/Inputs/modules/module.modulemap new file mode 100644 index 0000000000..5590b43a2d --- /dev/null +++ b/test/PCH/Inputs/modules/module.modulemap @@ -0,0 +1,3 @@ +module Foo { + header "Foo.h" +} diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp index 52ea8752b3..d50eee0623 100644 --- a/test/PCH/cxx-templates.cpp +++ b/test/PCH/cxx-templates.cpp @@ -10,7 +10,7 @@ // Test with modules. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s -ast-dump -o - -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s // Test with pch and delayed template parsing. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h diff --git a/test/PCH/module-hash-difference.m b/test/PCH/module-hash-difference.m new file mode 100644 index 0000000000..073540eb54 --- /dev/null +++ b/test/PCH/module-hash-difference.m @@ -0,0 +1,8 @@ +// RUN: rm -rf %t.mcp +// RUN: rm -rf %t.err +// RUN: %clang_cc1 -emit-pch -o %t.pch %s -I %S/Inputs/modules -fmodules -fmodules-cache-path=%t.mcp +// RUN: not %clang_cc1 -fsyntax-only -include-pch %t.pch %s -I %S/Inputs/modules -fmodules -fmodules-cache-path=%t.mcp -fdisable-module-hash 2> %t.err +// RUN: FileCheck -input-file=%t.err %s + +// CHECK: error: PCH was compiled with module cache path {{.*}}, but the path is currently {{.*}} +@import Foo;