Skip to content

Commit 4250c0e

Browse files
authored
Fix crashing name mangler (#1910)
* Fix broken name mangler * Remove llvm backend mangeling
1 parent cbaf344 commit 4250c0e

File tree

4 files changed

+214
-49
lines changed

4 files changed

+214
-49
lines changed

src/CppParser/ASTNameMangler.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/************************************************************************
2+
*
3+
* CppSharp
4+
* Licensed under the simplified BSD license. All rights reserved.
5+
*
6+
************************************************************************/
7+
8+
#include "ASTNameMangler.h"
9+
10+
#include <clang/AST/GlobalDecl.h>
11+
#include <clang/AST/Mangle.h>
12+
#include <clang/AST/VTableBuilder.h>
13+
#include <clang/Basic/TargetInfo.h>
14+
#include <llvm/IR/Mangler.h>
15+
16+
using namespace clang;
17+
using namespace CppSharp::CppParser;
18+
19+
namespace {
20+
enum ObjCKind {
21+
ObjCClass,
22+
ObjCMetaclass,
23+
};
24+
25+
StringRef getClassSymbolPrefix(ObjCKind Kind, const ASTContext& Context) {
26+
if (Context.getLangOpts().ObjCRuntime.isGNUFamily())
27+
return Kind == ObjCMetaclass ? "_OBJC_METACLASS_" : "_OBJC_CLASS_";
28+
return Kind == ObjCMetaclass ? "OBJC_METACLASS_$_" : "OBJC_CLASS_$_";
29+
}
30+
31+
void WriteObjCClassName(const ObjCInterfaceDecl* D, raw_ostream& OS) {
32+
OS << getClassSymbolPrefix(ObjCClass, D->getASTContext());
33+
OS << D->getObjCRuntimeNameAsString();
34+
}
35+
}
36+
37+
ASTNameMangler::ASTNameMangler(ASTContext& Ctx)
38+
: DL(Ctx.getTargetInfo().getDataLayoutString())
39+
, MC(Ctx.createMangleContext())
40+
{
41+
}
42+
43+
std::string ASTNameMangler::GetName(const Decl* D) {
44+
std::string Name;
45+
{
46+
llvm::raw_string_ostream OS(Name);
47+
WriteName(D, OS);
48+
}
49+
return Name;
50+
}
51+
52+
bool ASTNameMangler::WriteName(const Decl* D, raw_ostream& OS) {
53+
// First apply frontend mangling.
54+
if (auto* FD = dyn_cast<FunctionDecl>(D)) {
55+
if (FD->isDependentContext())
56+
return true;
57+
if (WriteFuncOrVarName(FD, OS))
58+
return true;
59+
}
60+
else if (auto* VD = dyn_cast<VarDecl>(D)) {
61+
if (WriteFuncOrVarName(VD, OS))
62+
return true;
63+
}
64+
else if (auto* MD = dyn_cast<ObjCMethodDecl>(D)) {
65+
MC->mangleObjCMethodName(MD, OS, /*includePrefixByte=*/false,
66+
/*includeCategoryNamespace=*/true);
67+
return false;
68+
}
69+
else if (auto* ID = dyn_cast<ObjCInterfaceDecl>(D)) {
70+
WriteObjCClassName(ID, OS);
71+
}
72+
else {
73+
return true;
74+
}
75+
76+
return false;
77+
}
78+
79+
std::string ASTNameMangler::GetMangledStructor(const NamedDecl* ND, unsigned StructorType) {
80+
std::string FrontendBuf;
81+
llvm::raw_string_ostream FOS(FrontendBuf);
82+
83+
GlobalDecl GD;
84+
if (const auto* CD = dyn_cast_or_null<CXXConstructorDecl>(ND))
85+
GD = GlobalDecl(CD, static_cast<CXXCtorType>(StructorType));
86+
else if (const auto* DD = dyn_cast_or_null<CXXDestructorDecl>(ND))
87+
GD = GlobalDecl(DD, static_cast<CXXDtorType>(StructorType));
88+
MC->mangleName(GD, FOS);
89+
90+
return FrontendBuf;
91+
}
92+
93+
std::string ASTNameMangler::GetMangledThunk(const CXXMethodDecl* MD, const ThunkInfo& T, bool /*ElideOverrideInfo*/) {
94+
std::string FrontendBuf;
95+
llvm::raw_string_ostream FOS(FrontendBuf);
96+
97+
// TODO: Enable `ElideOverrideInfo` param if clang is updated to 19
98+
MC->mangleThunk(MD, T, /*ElideOverrideInfo,*/ FOS);
99+
100+
return FrontendBuf;
101+
}
102+
103+
bool ASTNameMangler::WriteFuncOrVarName(const NamedDecl* D, raw_ostream& OS) const
104+
{
105+
if (!MC->shouldMangleDeclName(D)) {
106+
const IdentifierInfo* II = D->getIdentifier();
107+
if (!II)
108+
return true;
109+
OS << II->getName();
110+
return false;
111+
}
112+
113+
GlobalDecl GD;
114+
if (const auto* CtorD = dyn_cast<CXXConstructorDecl>(D))
115+
GD = GlobalDecl(CtorD, Ctor_Base);
116+
else if (const auto* DtorD = dyn_cast<CXXDestructorDecl>(D))
117+
GD = GlobalDecl(DtorD, Dtor_Base);
118+
else if (D->hasAttr<CUDAGlobalAttr>())
119+
GD = GlobalDecl(cast<FunctionDecl>(D));
120+
else
121+
GD = GlobalDecl(D);
122+
123+
MC->mangleName(GD, OS);
124+
return false;
125+
}

src/CppParser/ASTNameMangler.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/************************************************************************
2+
*
3+
* CppSharp
4+
* Licensed under the simplified BSD license. All rights reserved.
5+
*
6+
************************************************************************/
7+
8+
#pragma once
9+
10+
#include <clang/AST/ASTFwd.h>
11+
#include <llvm/IR/DataLayout.h>
12+
13+
#include <string>
14+
15+
namespace clang
16+
{
17+
class ASTContext;
18+
class MangleContext;
19+
struct ThunkInfo;
20+
}
21+
22+
namespace llvm
23+
{
24+
class raw_ostream;
25+
}
26+
27+
namespace CppSharp::CppParser {
28+
29+
/// <summary>
30+
/// Helper class for getting the mangled name of a declaration
31+
/// </summary>
32+
/// <remarks>Source adapted from https://clang.llvm.org/doxygen/Mangle_8cpp_source.html#l00394</remarks>
33+
class ASTNameMangler
34+
{
35+
public:
36+
explicit ASTNameMangler(clang::ASTContext& Ctx);
37+
38+
std::string GetName(const clang::Decl* D);
39+
bool WriteName(const clang::Decl* D, llvm::raw_ostream& OS);
40+
41+
private:
42+
std::string GetMangledStructor(const clang::NamedDecl* ND, unsigned StructorType);
43+
std::string GetMangledThunk(const clang::CXXMethodDecl* MD, const clang::ThunkInfo& T, bool ElideOverrideInfo);
44+
bool WriteFuncOrVarName(const clang::NamedDecl* D, llvm::raw_ostream& OS) const;
45+
46+
llvm::DataLayout DL;
47+
std::unique_ptr<clang::MangleContext> MC;
48+
};
49+
50+
}

src/CppParser/Parser.cpp

Lines changed: 35 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
#include <Driver/ToolChains/Linux.h>
5959
#include <Driver/ToolChains/MSVC.h>
6060

61+
#include "ASTNameMangler.h"
62+
6163
#if defined(__APPLE__) || defined(__linux__)
6264
#ifndef _GNU_SOURCE
6365
#define _GNU_SOURCE
@@ -468,69 +470,55 @@ void Parser::Setup(bool Compile)
468470
PP.getLangOpts());
469471

470472
c->createASTContext();
473+
NameMangler.reset(new ASTNameMangler(c->getASTContext()));
471474
}
472475

473476
//-----------------------------------//
474477

475-
std::string Parser::GetDeclMangledName(const clang::Decl* D)
478+
std::string Parser::GetDeclMangledName(const clang::Decl* D) const
476479
{
477-
using namespace clang;
480+
// Source adapted from https://clang.llvm.org/doxygen/JSONNodeDumper_8cpp_source.html#l00845
478481

479-
if(!D || !isa<NamedDecl>(D))
480-
return "";
482+
using namespace clang;
481483

482-
bool CanMangle = isa<FunctionDecl>(D) || isa<VarDecl>(D)
483-
|| isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D);
484+
auto ND = dyn_cast_or_null<NamedDecl>(D);
485+
if (!ND || !ND->getDeclName())
486+
return {};
484487

485-
if (!CanMangle) return "";
488+
// If the declaration is dependent or is in a dependent context, then the
489+
// mangling is unlikely to be meaningful (and in some cases may cause
490+
// "don't know how to mangle this" assertion failures.)
491+
if (ND->isTemplated())
492+
return {};
486493

487-
auto ND = cast<NamedDecl>(D);
488-
std::unique_ptr<MangleContext> MC;
489-
490-
auto& AST = c->getASTContext();
491-
auto targetABI = c->getTarget().getCXXABI().getKind();
492-
switch(targetABI)
493-
{
494-
default:
495-
MC.reset(ItaniumMangleContext::create(AST, AST.getDiagnostics()));
496-
break;
497-
case TargetCXXABI::Microsoft:
498-
MC.reset(MicrosoftMangleContext::create(AST, AST.getDiagnostics()));
499-
break;
500-
}
501-
502-
if (!MC)
503-
llvm_unreachable("Unknown mangling ABI");
504-
505-
std::string Mangled;
506-
llvm::raw_string_ostream Out(Mangled);
494+
/*bool CanMangle = isa<FunctionDecl>(D) || isa<VarDecl>(D)
495+
|| isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D);
507496
508-
bool IsDependent = false;
509-
if (const ValueDecl *VD = dyn_cast<ValueDecl>(ND))
510-
IsDependent |= VD->getType()->isDependentType();
497+
if (!CanMangle)
498+
return {};*/
511499

512-
if (!IsDependent)
513-
IsDependent |= ND->getDeclContext()->isDependentContext();
500+
// FIXME: There are likely other contexts in which it makes no sense to ask
501+
// for a mangled name.
502+
if (isa<RequiresExprBodyDecl>(ND->getDeclContext()))
503+
return {};
514504

515-
if (!MC->shouldMangleDeclName(ND) || IsDependent)
516-
return ND->getDeclName().getAsString();
505+
// Do not mangle template deduction guides.
506+
if (isa<CXXDeductionGuideDecl>(ND))
507+
return {};
517508

518-
GlobalDecl GD;
519-
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(ND))
520-
GD = GlobalDecl(CD, Ctor_Base);
521-
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(ND))
522-
GD = GlobalDecl(DD, Dtor_Base);
523-
else
524-
GD = GlobalDecl(ND);
525-
MC->mangleName(GD, Out);
509+
// Mangled names are not meaningful for locals, and may not be well-defined
510+
// in the case of VLAs.
511+
auto* VD = dyn_cast<VarDecl>(ND);
512+
if (VD && VD->hasLocalStorage())
513+
return {};
526514

527-
Out.flush();
515+
std::string MangledName = NameMangler->GetName(ND);
528516

529517
// Strip away LLVM name marker.
530-
if(!Mangled.empty() && Mangled[0] == '\01')
531-
Mangled = Mangled.substr(1);
518+
if (!MangledName.empty() && MangledName[0] == '\01')
519+
MangledName = MangledName.substr(1);
532520

533-
return Mangled;
521+
return MangledName;
534522
}
535523

536524
//-----------------------------------//
@@ -632,7 +620,7 @@ static clang::SourceLocation GetDeclStartLocation(clang::CompilerInstance* C,
632620
return GetDeclStartLocation(C, prevDecl);
633621
}
634622

635-
std::string Parser::GetTypeName(const clang::Type* Type)
623+
std::string Parser::GetTypeName(const clang::Type* Type) const
636624
{
637625
using namespace clang;
638626

src/CppParser/Parser.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ namespace clang {
4747
#define Debug printf
4848

4949
namespace CppSharp { namespace CppParser {
50+
class ASTNameMangler;
5051

5152
class Parser
5253
{
@@ -133,8 +134,8 @@ class Parser
133134
// Clang helpers
134135
SourceLocationKind GetLocationKind(const clang::SourceLocation& Loc);
135136
bool IsValidDeclaration(const clang::SourceLocation& Loc);
136-
std::string GetDeclMangledName(const clang::Decl* D);
137-
std::string GetTypeName(const clang::Type* Type);
137+
std::string GetDeclMangledName(const clang::Decl* D) const;
138+
std::string GetTypeName(const clang::Type* Type) const;
138139
bool CanCheckCodeGenInfo(const clang::Type* Ty);
139140
void CompleteIfSpecializationType(const clang::QualType& QualType);
140141
Parameter* WalkParameter(const clang::ParmVarDecl* PVD,
@@ -181,6 +182,7 @@ class Parser
181182
int index;
182183
std::unique_ptr<clang::CompilerInstance> c;
183184
llvm::LLVMContext LLVMCtx;
185+
std::unique_ptr<ASTNameMangler> NameMangler;
184186
std::unique_ptr<llvm::Module> LLVMModule;
185187
std::unique_ptr<clang::CodeGen::CodeGenModule> CGM;
186188
std::unique_ptr<clang::CodeGen::CodeGenTypes> codeGenTypes;

0 commit comments

Comments
 (0)