[Frontend] Only compile modules if not already finalized
authorBen Barham <ben_barham@apple.com>
Fri, 16 Jul 2021 01:24:09 +0000 (18:24 -0700)
committerVolodymyr Sapsai <vsapsai@apple.com>
Fri, 16 Jul 2021 01:27:08 +0000 (18:27 -0700)
commit766a08df12c111b15ed51d0fcac06042d2f68cd6
tree5c1992bb428f9dfc537b6323dd4d122b681779ec
parent3c4023b225ace3a5c0ed23bc491b47c9dad4353c
[Frontend] Only compile modules if not already finalized

It was possible to re-add a module to a shared in-memory module cache
when search paths are changed. This can eventually cause a crash if the
original module is referenced after this occurs.
  1. Module A depends on B
  2. B exists in two paths C and D
  3. First run only has C on the search path, finds A and B and loads
     them
  4. Second run adds D to the front of the search path. A is loaded and
     contains a reference to the already compiled module from C. But
     searching finds the module from D instead, causing a mismatch
  5. B and the modules that depend on it are considered out of date and
     thus rebuilt
  6. The recompiled module A is added to the in-memory cache, freeing
     the previously inserted one

This can never occur from a regular clang process, but is very easy to
do through the API - whether through the use of a shared case or just
running multiple compilations from a single `CompilerInstance`. Update
the compilation to return early if a module is already finalized so that
the pre-condition in the in-memory module cache holds.

Resolves rdar://78180255

Differential Revision: https://reviews.llvm.org/D105328
clang/include/clang/Basic/DiagnosticCommonKinds.td
clang/include/clang/Basic/DiagnosticSerializationKinds.td
clang/include/clang/Serialization/ASTReader.h
clang/lib/Frontend/CompilerInstance.cpp
clang/lib/Serialization/ASTReader.cpp
clang/unittests/Serialization/CMakeLists.txt
clang/unittests/Serialization/ModuleCacheTest.cpp [new file with mode: 0644]