From mboxrd@z Thu Jan 1 00:00:00 1970 X-Received: by 2002:a05:620a:460a:b0:778:959e:877b with SMTP id br10-20020a05620a460a00b00778959e877bmr392589qkb.13.1698927609496; Thu, 02 Nov 2023 05:20:09 -0700 (PDT) X-Received: by 2002:a05:6870:6193:b0:1e9:8db0:383 with SMTP id a19-20020a056870619300b001e98db00383mr8912117oah.1.1698927609235; Thu, 02 Nov 2023 05:20:09 -0700 (PDT) Path: eternal-september.org!news.eternal-september.org!feeder2.eternal-september.org!eternal-september.org!news.mixmin.net!proxad.net!feeder1-2.proxad.net!209.85.160.216.MISMATCH!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail Newsgroups: comp.lang.ada Date: Thu, 2 Nov 2023 05:20:08 -0700 (PDT) Injection-Info: google-groups.googlegroups.com; posting-host=67.77.21.19; posting-account=ahMziQoAAAAL0iwU2Gxnh6xZxKmkLfTD NNTP-Posting-Host: 67.77.21.19 User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: Subject: Upcasting interfaces with CPP convention in GNAT From: Kura Injection-Date: Thu, 02 Nov 2023 12:20:09 +0000 Content-Type: text/plain; charset="UTF-8" Xref: news.eternal-september.org comp.lang.ada:65826 List-Id: Hi all, I'm trying to figure out how to correctly perform an upcast in GNAT using interface types that have the CPP convention. I have two types corresponding to C++ classes: IBase and IDerived each with corresponding access types suffixed with _Ptr. The library that I'm wrapping returns a pointer to some concrete implementation of IDerived, but the moment I convert it to an IBase_Ptr to pass it to functions within the library, the program segfaults while performing some kind of tag check. I've found information on this topic to be very sparse, and the GNAT manual has no discussion about allowed conversions or examples showing how to do this. This seems like it should be an allowed conversion and the program works as expected if I either replace the usage of Base_Ptr with Derived_Ptr within the function wrapper specification (not feasible because there are many types deriving from Base_Ptr and adding overloads would affect its vtable) or use Unchecked_Conversion between the two pointer types (unsure if this is safe). I'm also aware I could lay out the vtables manually and do away with tagged types, but I would like to avoid that if possible. Here is a minimal example that segfaults, all compiled with the same toolchain on windows/mingw64: --==== repro.adb ============================================================== with Wrap; use Wrap; procedure Repro is P : IDerived_Ptr := GetDerivedInstance; Q : IBase_Ptr := IBase_Ptr (P); begin null; end Repro; --==== wrap.ads =============================================================== package Wrap is type IBase is interface; pragma Convention (C_Plus_Plus, IBase); type IBase_Ptr is access all IBase'Class; type IDerived is interface and IBase; pragma Convention (C_Plus_Plus, IDerived); type IDerived_Ptr is access all IDerived'Class; function GetDerivedInstance return IDerived_Ptr with Import => True, Convention => C_Plus_Plus, External_Name => "GetDerivedInstance"; end Wrap; --==== lib.cpp ================================================================ class IBase {}; class IDerived : public IBase {}; class Impl : public IDerived { public: Impl() = default; }; extern "C" IDerived* GetDerivedInstance() { return new Impl(); } --==== end example ============================================================ Error and stack trace: Thread 1 received signal SIGSEGV, Segmentation fault. ada.tags.offset_to_top (this=(system.address) 0x6591710) at a-tags.adb:806 806 a-tags.adb: No such file or directory. (gdb) bt #0 ada.tags.offset_to_top (this=(system.address) 0x6591710) at a-tags.adb:806 #1 ada.tags.base_address (this=(system.address) 0x6591710) at a-tags.adb:286 #2 ada.tags.displace (this=(system.address) 0x6591710, t=0x7ff7fe8301c8 (wrap.ibase)) at a-tags.adb:354 #3 0x00007ff7fe82649c in repro () at C:\repro\src\repro.adb:5 Any ideas?