Search code examples
c++adagnat

How to deallocate Ada Record from CPP


I am attempting to free a heap allocated Ada tagged record from cpp. I have used the code AdacoreU as a starting place.

I receive the following error when running the code below.

20
double free or corruption (out)

raised PROGRAM_ERROR : unhandled signal

Am I overthinking things? Do I need an Ada based deallocation mechanism.

What is my real end goal? I would like to use dynamic libraries to create a plugin infrastructure where each library is its own factory for a given type. Something along the lines of boost dll but with ada based dynamic libraries.

Modified Code below:

main.cpp

  1 #include <iostream>
  2 #include "animal.h"
  3 
  4 extern "C" {
  5     void adainit (void);
  6     void adafinal (void);
  7     Animal* new_animal();
  8     void del_animal(Animal *);
  9 }
 10 
 11 int main(void) {
 12     adainit();
 13     Animal* A = new_animal();
 14     std::cout << A->age() << std::endl;
 15     //delete A;   
 16     del_animal(A);
 17     adafinal();
 18     return 0;
 19 };

alib.ads

  1 
  2 with Interfaces.C;
  3 
  4 package ALib is
  5 
  6     type Animal is tagged record
  7         The_Age : Interfaces.C.int;
  8     end record;
  9     pragma Convention (CPP, Animal);
 10 
 11     type Animal_Class_Access is access Animal'Class;
 12 
 13     function New_Animal return access Animal'Class;
 14     pragma Export(CPP, New_Animal);
 15 
 16     procedure Del_Animal (this : in out Animal_Class_Access);
 17     pragma Export(CPP, Del_Animal);
 18 
 19     function Age(X : Animal) return Interfaces.C.int;
 20     pragma Export(CPP, Age);
 21 
 22 end ALib;

alib.adb

  1 with ada.unchecked_deallocation;
  2 
  3 package body ALib is
  4 
  5     function New_Animal
  6         return access Animal'Class is
  7     begin
  8         return new Animal'(The_Age => 20);
  9     end New_Animal;
 10 
 11 
 12     procedure Del_Animal (this : in out Animal_Class_Access) is
 13         procedure Free is new ada.unchecked_deallocation(Animal'Class, Animal_Class_Access);
 14     begin
 15         Free(this);
 16         --null;
 17     end Del_Animal;
 18 
 19     function Age(X : Animal)
 20         return Interfaces.C.int is
 21     begin
 22         return X.The_Age;
 23     end Age;
 24 
 25 end ALib;
~              

other resources used as a starting point

3.11.3.5 Interfacing with C++ at the Class Level

What have I attempted:

  • Used various combinations of the type and access type when attempting to create the Free procedure
    • Animal, type Animal_Access is access Animal
    • Animal'Class, type Animal_Class_Access is access Animal'Class
    • Animal, type Animal_Access is access Animal'Class
  • I was at some point under the impression that I should be using system address for the pointers to the Animal object as either part of the return on New_Animal and as the argument to Del_Animal

What did I expect:

I expected to clean up Ada heap objects from Ada.


Solution

  • The problem is with the in out parameter to Del_Animal and its mapping to the C world.

    Your intention with Del_Animal is that it should behave like Ada.Unchecked_Deallocation, in other words that the parameter is set to null (or 0!) after the call, but that means that what you have to pass is the address of the actual.

    That is,

    void del_animal(Animal**);
    

    called as

    del_animal(&A);
    

    See ARM B3(68).