From 401e09f9ad1a01d689201fb62ccc5019800954d1 Mon Sep 17 00:00:00 2001 From: Eugene Shalygin Date: Fri, 25 Jun 2021 15:02:18 +0200 Subject: [PATCH] Handle virtual destructors in C++ classes This resolves crashing on virtual destructors if Clang is build with assertions and corrects vtbl indices for tables with destructors. Fixes #240. --- .../ClangSharp.Interop/CX_DestructorType.cs | 13 +++++ sources/ClangSharp.Interop/clangsharp.cs | 4 ++ sources/libClangSharp/ClangSharp.cpp | 52 +++++++++++++++---- sources/libClangSharp/ClangSharp.h | 13 +++++ 4 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 sources/ClangSharp.Interop/CX_DestructorType.cs diff --git a/sources/ClangSharp.Interop/CX_DestructorType.cs b/sources/ClangSharp.Interop/CX_DestructorType.cs new file mode 100644 index 00000000..b3fdfb34 --- /dev/null +++ b/sources/ClangSharp.Interop/CX_DestructorType.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft and Contributors. All rights reserved. Licensed under the University of Illinois/NCSA Open Source License. See LICENSE.txt in the project root for license information. +// Ported from https://github.com/microsoft/ClangSharp/blob/main/sources/libClangSharp + +namespace ClangSharp.Interop +{ + public enum CX_DestructorType + { + Deleting, + Complete, + Base, + Comdat + } +} diff --git a/sources/ClangSharp.Interop/clangsharp.cs b/sources/ClangSharp.Interop/clangsharp.cs index a601596b..28a270ed 100644 --- a/sources/ClangSharp.Interop/clangsharp.cs +++ b/sources/ClangSharp.Interop/clangsharp.cs @@ -865,6 +865,10 @@ public static partial class clangsharp [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getVBase", ExactSpelling = true)] public static extern CXCursor Cursor_getVBase(CXCursor C, [NativeTypeName("unsigned int")] uint i); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getDtorVtblIdx", ExactSpelling = true)] + [return: NativeTypeName("int64_t")] + public static extern long Cursor_getDtorVtblIdx(CXCursor C, CX_DestructorType dtor); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getVtblIdx", ExactSpelling = true)] [return: NativeTypeName("int64_t")] public static extern long Cursor_getVtblIdx(CXCursor C); diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index 3a134e7f..b6332d21 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -8,12 +8,16 @@ #include "CXTranslationUnit.h" #include "CXType.h" +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4146 4244 4267 4291 4624 4996) +#endif #include +#ifdef _MSC_VER #pragma warning(pop) +#endif using namespace clang; using namespace clang::cxcursor; @@ -61,6 +65,25 @@ bool isStmtOrExpr(CXCursorKind kind) { return clang_isStatement(kind) || clang_isExpression(kind); } +int64_t getVtblIdx(const GlobalDecl& d) +{ + const CXXMethodDecl* CMD = static_cast(d.getDecl()); + if (VTableContextBase::hasVtableSlot(CMD)) { + VTableContextBase* VTC = CMD->getASTContext().getVTableContext(); + + if (MicrosoftVTableContext* MSVTC = dyn_cast(VTC)) { + MethodVFTableLocation ML = MSVTC->getMethodVFTableLocation(d); + return ML.Index; + } + + if (ItaniumVTableContext* IVTC = dyn_cast(VTC)) { + return IVTC->getMethodVTableIndex(d); + } + } + + return -1; +} + CXCursor clangsharp_Cursor_getArgument(CXCursor C, unsigned i) { if (isDeclOrTU(C.kind)) { const Decl* D = getCursorDecl(C); @@ -4693,23 +4716,30 @@ CXCursor clangsharp_Cursor_getVBase(CXCursor C, unsigned i) { return clang_getNullCursor(); } -int64_t clangsharp_Cursor_getVtblIdx(CXCursor C) { +int64_t clangsharp_Cursor_getDtorVtblIdx(CXCursor C, CX_DestructorType dtor) +{ if (isDeclOrTU(C.kind)) { const Decl* D = getCursorDecl(C); - if (const CXXMethodDecl* CMD = dyn_cast(D)) { - if (VTableContextBase::hasVtableSlot(CMD)) { - VTableContextBase* VTC = getASTUnit(getCursorTU(C))->getASTContext().getVTableContext(); + if (const CXXDestructorDecl* CMD = dyn_cast(D)) { + return getVtblIdx(GlobalDecl(CMD, static_cast(dtor))); + } + } + return -1; +} - if (MicrosoftVTableContext* MSVTC = dyn_cast(VTC)) { - MethodVFTableLocation ML = MSVTC->getMethodVFTableLocation(CMD); - return ML.Index; - } +int64_t clangsharp_Cursor_getVtblIdx(CXCursor C) { + if (isDeclOrTU(C.kind)) { + const Decl* D = getCursorDecl(C); - if (ItaniumVTableContext* IVTC = dyn_cast(VTC)) { - return IVTC->getMethodVTableIndex(CMD); - } + if (const CXXMethodDecl* CMD = dyn_cast(D)) { + int64_t dtorIdx = clangsharp_Cursor_getDtorVtblIdx(C, Deleting); // will test if CMD is a dtor + if (dtorIdx != -1) { // yes, it is a dtor + return dtorIdx; } + + // no, it is a regular method + return getVtblIdx(CMD); } } diff --git a/sources/libClangSharp/ClangSharp.h b/sources/libClangSharp/ClangSharp.h index 9a018a99..a13642e2 100644 --- a/sources/libClangSharp/ClangSharp.h +++ b/sources/libClangSharp/ClangSharp.h @@ -3,8 +3,10 @@ #ifndef LIBCLANGSHARP_CLANGSHARP_H #define LIBCLANGSHARP_CLANGSHARP_H +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4146 4244 4267 4291 4624 4996) +#endif #include #include @@ -19,7 +21,9 @@ #include #include +#ifdef _MSC_VER #pragma warning(pop) +#endif #ifdef __cplusplus #define EXTERN_C extern "C" @@ -202,6 +206,13 @@ enum CX_VariableCaptureKind { CX_VCK_VLAType = clang::CapturedStmt::VCK_VLAType + 1 }; +enum CX_DestructorType { + Deleting = clang::Dtor_Deleting, + Complete = clang::Dtor_Complete, + Base = clang::Dtor_Base, + Comdat = clang::Dtor_Comdat +}; + struct CX_TemplateArgument { CXTemplateArgumentKind kind; int xdata; @@ -722,6 +733,8 @@ CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getUsedContext(CXCursor C); CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getVBase(CXCursor C, unsigned i); +CLANGSHARP_LINKAGE int64_t clangsharp_Cursor_getDtorVtblIdx(CXCursor C, CX_DestructorType dtor); + CLANGSHARP_LINKAGE int64_t clangsharp_Cursor_getVtblIdx(CXCursor C); CLANGSHARP_LINKAGE void clangsharp_TemplateArgument_dispose(CX_TemplateArgument T);