Skip to content

Commit f562b00

Browse files
committed
[clang][ASTImporter] Fix possible crash at import of function template
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 4109a51 commit f562b00

File tree

4 files changed

+103
-7
lines changed

4 files changed

+103
-7
lines changed

clang/lib/AST/ASTImporter.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6731,13 +6731,6 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
67316731
if (Error Err = importInto(TemplatedFD, D->getTemplatedDecl()))
67326732
return std::move(Err);
67336733

6734-
// Fail if TemplatedFD is already part of a template.
6735-
// The structural equivalence check should have been found this template.
6736-
// If not, there is AST incompatibility that can be caused by previous import
6737-
// errors.
6738-
if (TemplatedFD->getDescribedTemplate())
6739-
return make_error<ASTImportError>(ASTImportError::NameConflict);
6740-
67416734
// At creation of the template the template parameters are "adopted"
67426735
// (DeclContext is changed). After this possible change the lookup table
67436736
// must be updated.
@@ -6762,6 +6755,14 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
67626755
Params, TemplatedFD))
67636756
return ToFunc;
67646757

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

67676768
ToFunc->setAccess(D->getAccess());
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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+
template <typename _Ptr> using __ptr_traits_elem_t = __get_first_arg<_Ptr>;
9+
template <typename> struct __ptr_traits_impl;
10+
template <typename _Ptr>
11+
struct pointer_traits : __ptr_traits_impl<__ptr_traits_elem_t<_Ptr>> {};
12+
struct allocator_traits {
13+
using type = pointer_traits<int>;
14+
};
15+
} // namespace std
16+
namespace std {
17+
inline namespace __cxx11 {
18+
template <typename, typename, typename> class basic_string {
19+
allocator_traits _M_allocated_capacity;
20+
void _M_assign();
21+
};
22+
} // namespace __cxx11
23+
} // namespace std
24+
namespace std {
25+
template <typename _CharT, typename _Alloc> void operator!=(_Alloc, _CharT);
26+
template <typename _CharT, typename _Traits, typename _Alloc>
27+
basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &,
28+
basic_string<_CharT, _Traits, _Alloc> &,
29+
_CharT);
30+
} // namespace std
31+
namespace std {
32+
template <typename _CharT, typename _Traits, typename _Alloc>
33+
void basic_string<_CharT, _Traits, _Alloc>::_M_assign() {
34+
this != 0;
35+
}
36+
template <typename _CharT, typename _Traits, typename _Alloc>
37+
basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &,
38+
basic_string<_CharT, _Traits, _Alloc> &,
39+
_CharT) {}
40+
} // namespace std
41+
struct CommandLineOptionDefinition {
42+
void *OutAddress;
43+
};
44+
struct CommandLineCommand {
45+
CommandLineOptionDefinition Options;
46+
};
47+
namespace CommandLine {
48+
extern const CommandLineCommand RootCommands[];
49+
extern const int RootExamples[];
50+
} // namespace CommandLine
51+
using utf8 = char;
52+
using u8string = std::basic_string<utf8>;
53+
u8string _rct2DataPath;
54+
CommandLineOptionDefinition StandardOptions{&_rct2DataPath};
55+
const CommandLineCommand CommandLine::RootCommands[]{StandardOptions};
56+
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:18{{incompatible definitions}}
32+
// expected-warning@Inputs/ctu-test-import-failure-import.cpp:18{{incompatible definitions}}
33+
// expected-note@Inputs/ctu-test-import-failure-import.cpp:18{{no corresponding field here}}
34+
// expected-note@Inputs/ctu-test-import-failure-import.cpp:18{{no corresponding field here}}

0 commit comments

Comments
 (0)