https://github.com/balazske created https://github.com/llvm/llvm-project/pull/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. From 4109a5166b544c33af333505883b414db7c0c14d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.k...@ericsson.com> Date: Wed, 22 Jan 2025 17:55:51 +0100 Subject: [PATCH 1/2] fix test --- clang/lib/AST/ASTImporter.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 0669aa1b809c34..c25ec82c1ab5f9 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6731,6 +6731,13 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (Error Err = importInto(TemplatedFD, D->getTemplatedDecl())) return std::move(Err); + // Fail if TemplatedFD is already part of a template. + // The structural equivalence check should have been found this template. + // If not, there is AST incompatibility that can be caused by previous import + // errors. + if (TemplatedFD->getDescribedTemplate()) + return make_error<ASTImportError>(ASTImportError::NameConflict); + // At creation of the template the template parameters are "adopted" // (DeclContext is changed). After this possible change the lookup table // must be updated. From f562b00b74ddf011134d5b2c06be95bc9a0fb046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.k...@ericsson.com> Date: Fri, 24 Jan 2025 11:43:38 +0100 Subject: [PATCH 2/2] [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. --- clang/lib/AST/ASTImporter.cpp | 15 ++--- .../Inputs/ctu-test-import-failure-import.cpp | 56 +++++++++++++++++++ ...ure-import.cpp.externalDefMap.ast-dump.txt | 5 ++ .../test/Analysis/ctu-test-import-failure.cpp | 34 +++++++++++ 4 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp create mode 100644 clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt create mode 100644 clang/test/Analysis/ctu-test-import-failure.cpp diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index c25ec82c1ab5f9..34b49963c00ec1 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6731,13 +6731,6 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (Error Err = importInto(TemplatedFD, D->getTemplatedDecl())) return std::move(Err); - // Fail if TemplatedFD is already part of a template. - // The structural equivalence check should have been found this template. - // If not, there is AST incompatibility that can be caused by previous import - // errors. - if (TemplatedFD->getDescribedTemplate()) - return make_error<ASTImportError>(ASTImportError::NameConflict); - // At creation of the template the template parameters are "adopted" // (DeclContext is changed). After this possible change the lookup table // must be updated. @@ -6762,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()); diff --git a/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp b/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp new file mode 100644 index 00000000000000..d5e6ba8852872e --- /dev/null +++ b/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp @@ -0,0 +1,56 @@ +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; +template <typename _Ptr> using __ptr_traits_elem_t = __get_first_arg<_Ptr>; +template <typename> struct __ptr_traits_impl; +template <typename _Ptr> +struct pointer_traits : __ptr_traits_impl<__ptr_traits_elem_t<_Ptr>> {}; +struct allocator_traits { + using type = pointer_traits<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[]{}; diff --git a/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt b/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt new file mode 100644 index 00000000000000..6ffb3795d3e36a --- /dev/null +++ b/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt @@ -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 \ No newline at end of file diff --git a/clang/test/Analysis/ctu-test-import-failure.cpp b/clang/test/Analysis/ctu-test-import-failure.cpp new file mode 100644 index 00000000000000..c586b9aa9a3107 --- /dev/null +++ b/clang/test/Analysis/ctu-test-import-failure.cpp @@ -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:18{{incompatible definitions}} +// expected-warning@Inputs/ctu-test-import-failure-import.cpp:18{{incompatible definitions}} +// expected-note@Inputs/ctu-test-import-failure-import.cpp:18{{no corresponding field here}} +// expected-note@Inputs/ctu-test-import-failure-import.cpp:18{{no corresponding field here}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits