Freeing a string (allocated in Ada) in a C function using free()

我怕爱的太早我们不能终老 提交于 2020-02-03 09:03:33

问题


I am working on a C-Ada binding application, where I am allocating a new string in Ada side using Interfaces.C.Strings.New_String().

Interfaces.C.Strings already has a procedure Free() to deallocate the memory for string. Since I need to pass this string to a C function using Interfaces.C.Strings.Chars_Ptr:

  1. Is it OK if I deallocate memory for the string in C side using the free() function (declared in stdlib.h)?

  2. Is it safe if I free the memory from C side?

  3. Or I should better free it using the Interfaces.C.Strings.Free() function from Ada side?


回答1:


There are two problems with calling Interfaces.C.Strings.Free from the C side.

The first is that the procedure has Convention Ada, so you can’t be sure of how to call it from C, even if your compiler is GNAT & therefore GCC-based; and you can’t change this without editing and rebuilding the standard library.

The second is that its declaration is

procedure Free (Item : in out chars_ptr);

which means that Item is passed by reference (char **item) so that it can be nulled.

You could arrange for the C side to call the Ada deallocation with wrapping. My view is that the Ada semantics (after Free (Item), Item is set to Null_Ptr) should be preserved, which means that the consuming C procedure to be called needs to take an in out parameter, translated as char **.

with Interfaces.C.Strings;
package String_Freeing is

   procedure C_Consumer (Item : in out Interfaces.C.Strings.chars_ptr)
   with
     Import,
     Convention => C,
     External_Name => "c_consumer";

   procedure Free_Wrapper (Item : in out Interfaces.C.Strings.chars_ptr)
   with
     Export,
     Convention => C,
     External_Name => "free_ada_string";

end String_Freeing;

(Free_Wrapper has to be in a package to be exported), with body

package body String_Freeing is
   procedure Free_Wrapper (Item : in out Interfaces.C.Strings.chars_ptr) is
   begin
      Interfaces.C.Strings.Free (Item);
   end Free_Wrapper;
end String_Freeing;

and test program

with Interfaces.C.Strings;
with String_Freeing; use String_Freeing;
procedure Test_String_Freeing is
   Str : Interfaces.C.Strings.chars_ptr;
   use type Interfaces.C.Strings.chars_ptr;
begin
   Str := Interfaces.C.Strings.New_String ("hello world.");
   C_Consumer (Str);
   pragma Assert (Str = Interfaces.C.Strings.Null_Ptr, "str not nulled");
end Test_String_Freeing;

where the C side of things might be

#include <stdio.h>

extern void free_ada_string(char **item);

void c_consumer(char **item) {
  printf("%s\n", *item);
  free_ada_string(item);
}

If you’re willing to leave dangling pointers on the Ada side, you could pass the string as an in (char *) parameter, which would make Free_Wrapper look like

package body String_Freeing is
   procedure Free_Wrapper (Item : Interfaces.C.Strings.chars_ptr) is
      Dummy : Interfaces.C.Strings.chars_ptr := Item;
   begin
      Interfaces.C.Strings.Free (Dummy);
   end Free_Wrapper;
end String_Freeing;

(spec to be changed to match, of course).




回答2:


You shall free this string on the Ada side:

  • the Ada API foresees this, so it's safe
  • the Ada API doesn't give any assurance that the memory is allocated using the C standard library (see package reference)
  • you don't know if the internals of the Ada implementation that you use makes use of the standard C library, or if it has its own memory management. So it would be extremely risky to free it on the C side, because freeing a pointer that was not allocated with malloc/calloc is undefined behavior.


来源:https://stackoverflow.com/questions/36133030/freeing-a-string-allocated-in-ada-in-a-c-function-using-free

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!