Skip to content

[clang][ASTImporter] Fix possible crash at import of function template #124273

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6755,6 +6755,14 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
Params, TemplatedFD))
return ToFunc;

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

TemplatedFD->setDescribedFunctionTemplate(ToFunc);

ToFunc->setAccess(D->getAccess());
Expand Down
52 changes: 52 additions & 0 deletions clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
namespace std {
inline namespace __cxx11 {
template <typename _CharT, typename = int, typename = _CharT>
class basic_string;
}
template <typename, typename> class basic_istream;
template <typename> struct __get_first_arg;
struct allocator_traits {
using type = __get_first_arg<int>;
};
} // namespace std
namespace std {
inline namespace __cxx11 {
template <typename, typename, typename> class basic_string {
allocator_traits _M_allocated_capacity;
void _M_assign();
};
} // namespace __cxx11
} // namespace std
namespace std {
template <typename _CharT, typename _Alloc> void operator!=(_Alloc, _CharT);
template <typename _CharT, typename _Traits, typename _Alloc>
basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &,
basic_string<_CharT, _Traits, _Alloc> &,
_CharT);
} // namespace std
namespace std {
template <typename _CharT, typename _Traits, typename _Alloc>
void basic_string<_CharT, _Traits, _Alloc>::_M_assign() {
this != 0;
}
template <typename _CharT, typename _Traits, typename _Alloc>
basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &,
basic_string<_CharT, _Traits, _Alloc> &,
_CharT) {}
} // namespace std
struct CommandLineOptionDefinition {
void *OutAddress;
};
struct CommandLineCommand {
CommandLineOptionDefinition Options;
};
namespace CommandLine {
extern const CommandLineCommand RootCommands[];
extern const int RootExamples[];
} // namespace CommandLine
using utf8 = char;
using u8string = std::basic_string<utf8>;
u8string _rct2DataPath;
CommandLineOptionDefinition StandardOptions{&_rct2DataPath};
const CommandLineCommand CommandLine::RootCommands[]{StandardOptions};
const int CommandLine::RootExamples[]{};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
47:c:@N@std@S@allocator_traits@F@allocator_traits# ctu-test-import-failure-import.cpp.ast
29:c:@N@CommandLine@RootCommands ctu-test-import-failure-import.cpp.ast
55:c:@N@std@N@__cxx11@ST>3#T#T#T@basic_string@F@_M_assign# ctu-test-import-failure-import.cpp.ast
97:c:@S@CommandLineOptionDefinition@F@CommandLineOptionDefinition#&1$@S@CommandLineOptionDefinition# ctu-test-import-failure-import.cpp.ast
29:c:@N@CommandLine@RootExamples ctu-test-import-failure-import.cpp.ast
34 changes: 34 additions & 0 deletions clang/test/Analysis/ctu-test-import-failure.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// RUN: rm -rf %t && mkdir %t
// RUN: mkdir -p %t/ctudir
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++17 \
// RUN: -emit-pch -o %t/ctudir/ctu-test-import-failure-import.cpp.ast %S/Inputs/ctu-test-import-failure-import.cpp
// RUN: cp %S/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt %t/ctudir/externalDefMap.txt
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++17 -analyze \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \
// RUN: -analyzer-config ctu-dir=%t/ctudir \
// RUN: -verify %s

// Check that importing this code does not cause crash.
// Import intentionally fails because mismatch of '__get_first_arg'.

namespace std {
inline namespace __cxx11 {}
template <typename _CharT, typename> class basic_istream;
struct __get_first_arg;
inline namespace __cxx11 {
template <typename, typename, typename> class basic_string;
}
template <typename _CharT, typename _Traits, typename _Alloc>
basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &,
basic_string<_CharT, _Traits, _Alloc> &,
_CharT) {}
} // namespace std
namespace CommandLine {
extern const int RootExamples[];
}

// expected-warning@Inputs/ctu-test-import-failure-import.cpp:14{{incompatible definitions}}
// expected-warning@Inputs/ctu-test-import-failure-import.cpp:14{{incompatible definitions}}
// expected-note@Inputs/ctu-test-import-failure-import.cpp:14{{no corresponding field here}}
// expected-note@Inputs/ctu-test-import-failure-import.cpp:14{{no corresponding field here}}
Loading