Skip to content

Commit 8e97f50

Browse files
authored
[clang][ASTImporter] Fix possible crash at import of function template (llvm#124273)
During import of a function template at specific conditions an assertion "TemplateOrSpecialization.isNull()" can be triggered. This can happen when the new AST is already incompatible after import failures. Problem is fixed by returning import failure at the assert condition.
1 parent c8d3ccf commit 8e97f50

File tree

4 files changed

+99
-0
lines changed

4 files changed

+99
-0
lines changed

clang/lib/AST/ASTImporter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6759,6 +6759,14 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
67596759
Params, TemplatedFD))
67606760
return ToFunc;
67616761

6762+
// Fail if TemplatedFD is already part of a template.
6763+
// The template should have been found by structural equivalence check before,
6764+
// or ToFunc should be already imported.
6765+
// If not, there is AST incompatibility that can be caused by previous import
6766+
// errors. (NameConflict is not exact here.)
6767+
if (TemplatedFD->getDescribedTemplate())
6768+
return make_error<ASTImportError>(ASTImportError::NameConflict);
6769+
67626770
TemplatedFD->setDescribedFunctionTemplate(ToFunc);
67636771

67646772
ToFunc->setAccess(D->getAccess());
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
namespace std {
2+
inline namespace __cxx11 {
3+
template <typename _CharT, typename = int, typename = _CharT>
4+
class basic_string;
5+
}
6+
template <typename, typename> class basic_istream;
7+
template <typename> struct __get_first_arg;
8+
struct allocator_traits {
9+
using type = __get_first_arg<int>;
10+
};
11+
} // namespace std
12+
namespace std {
13+
inline namespace __cxx11 {
14+
template <typename, typename, typename> class basic_string {
15+
allocator_traits _M_allocated_capacity;
16+
void _M_assign();
17+
};
18+
} // namespace __cxx11
19+
} // namespace std
20+
namespace std {
21+
template <typename _CharT, typename _Alloc> void operator!=(_Alloc, _CharT);
22+
template <typename _CharT, typename _Traits, typename _Alloc>
23+
basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &,
24+
basic_string<_CharT, _Traits, _Alloc> &,
25+
_CharT);
26+
} // namespace std
27+
namespace std {
28+
template <typename _CharT, typename _Traits, typename _Alloc>
29+
void basic_string<_CharT, _Traits, _Alloc>::_M_assign() {
30+
this != 0;
31+
}
32+
template <typename _CharT, typename _Traits, typename _Alloc>
33+
basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &,
34+
basic_string<_CharT, _Traits, _Alloc> &,
35+
_CharT) {}
36+
} // namespace std
37+
struct CommandLineOptionDefinition {
38+
void *OutAddress;
39+
};
40+
struct CommandLineCommand {
41+
CommandLineOptionDefinition Options;
42+
};
43+
namespace CommandLine {
44+
extern const CommandLineCommand RootCommands[];
45+
extern const int RootExamples[];
46+
} // namespace CommandLine
47+
using utf8 = char;
48+
using u8string = std::basic_string<utf8>;
49+
u8string _rct2DataPath;
50+
CommandLineOptionDefinition StandardOptions{&_rct2DataPath};
51+
const CommandLineCommand CommandLine::RootCommands[]{StandardOptions};
52+
const int CommandLine::RootExamples[]{};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
47:c:@N@std@S@allocator_traits@F@allocator_traits# ctu-test-import-failure-import.cpp.ast
2+
29:c:@N@CommandLine@RootCommands ctu-test-import-failure-import.cpp.ast
3+
55:c:@N@std@N@__cxx11@ST>3#T#T#T@basic_string@F@_M_assign# ctu-test-import-failure-import.cpp.ast
4+
97:c:@S@CommandLineOptionDefinition@F@CommandLineOptionDefinition#&1$@S@CommandLineOptionDefinition# ctu-test-import-failure-import.cpp.ast
5+
29:c:@N@CommandLine@RootExamples ctu-test-import-failure-import.cpp.ast
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: rm -rf %t && mkdir %t
2+
// RUN: mkdir -p %t/ctudir
3+
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++17 \
4+
// RUN: -emit-pch -o %t/ctudir/ctu-test-import-failure-import.cpp.ast %S/Inputs/ctu-test-import-failure-import.cpp
5+
// RUN: cp %S/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt %t/ctudir/externalDefMap.txt
6+
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++17 -analyze \
7+
// RUN: -analyzer-checker=core \
8+
// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \
9+
// RUN: -analyzer-config ctu-dir=%t/ctudir \
10+
// RUN: -verify %s
11+
12+
// Check that importing this code does not cause crash.
13+
// Import intentionally fails because mismatch of '__get_first_arg'.
14+
15+
namespace std {
16+
inline namespace __cxx11 {}
17+
template <typename _CharT, typename> class basic_istream;
18+
struct __get_first_arg;
19+
inline namespace __cxx11 {
20+
template <typename, typename, typename> class basic_string;
21+
}
22+
template <typename _CharT, typename _Traits, typename _Alloc>
23+
basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &,
24+
basic_string<_CharT, _Traits, _Alloc> &,
25+
_CharT) {}
26+
} // namespace std
27+
namespace CommandLine {
28+
extern const int RootExamples[];
29+
}
30+
31+
// expected-warning@Inputs/ctu-test-import-failure-import.cpp:14{{incompatible definitions}}
32+
// expected-warning@Inputs/ctu-test-import-failure-import.cpp:14{{incompatible definitions}}
33+
// expected-note@Inputs/ctu-test-import-failure-import.cpp:14{{no corresponding field here}}
34+
// expected-note@Inputs/ctu-test-import-failure-import.cpp:14{{no corresponding field here}}

0 commit comments

Comments
 (0)