Re: C chars_ptr STORAGE_ERROR in Imported function



Kim Rostgaard Christensen wrote:
Niklas Holsti wrote:

Kim Rostgaard Christensen wrote:

Hello there

I am in progress of binding the pcap c library to ada, it is a part of a
school project. And for that i need a funtion that modifies a parameter to a function like so:

char *pcap_lookupdev(char *);

...

the following gives me
*** glibc detected *** double free or corruption (out): 0x0804d830 ***

raised PROGRAM_ERROR : unhandled signal

procedure Lookup_Device is
function pcap_lookupdev(ebuff : Interfaces.C.Strings.Chars_Ptr) return Interfaces.C.Strings.Chars_Ptr;
pragma Import (C, pcap_lookupdev, "pcap_lookupdev");

Device : Interfaces.C.Strings.Chars_Ptr;
Errbuf_ptr : Interfaces.C.Strings.Chars_Ptr;
Errbuf : Char_Array(1 .. 256); -- the defined buffer size
begin

The problem is here:

Errbuf_Ptr := New_Char_Array(Errbuf);

New_Char_Array allocates a new char_array object, containing only the NUL-terminated string that is in Errbuf at this time. Since you have left Errbuf uninitialized, this may be a lot less than 256 characters, so the errors are probably due to buffer overflow somewhere in the pcap library where it tries to put an error message into the char_array that Errrbuf_Ptr points to, but this char_array is too small.

If you want to continue with New_Char_Array, you should initialize Errbuf to contain a 256-character string:

Errbuf : Char_Array (1 .. 256) := (
others => Interfaces.C.To_C (' '));

or perhaps neater, but more complex, a NUL-terminated 255-character string:

Errbuf : Char_Array (1 .. 256) := (
1 .. 255 => Interfaces.C.To_C (' '),
256 => Interfaces.C.nul);

Then New_Char_Array(Errbuf) will create a 256-character char_array that has room for the error message. (It works for me.)

If you use New_Char_Array you should also deallocate the new char_array by calling Interfaces.C.Strings.Free (Errbuf_Ptr) at a suitable point, when you no longer need this char_array.

I think it would be better to use the To_Chars_Ptr function, which makes a chars_ptr that points to Errbuf itself, without allocating another char_array, so there is no need to Free anything. This also needs a change in the declaration of Errbuf:

Errbuf : aliased Char_Array := (1 .. 256 => Interfaces.C.nul);

The initial values (here nul) are irrelevant, as long as there are 256 of them.

Then you replace the call of New_Char_Array with To_Chars_Ptr:

Errbuf_Ptr := To_Chars_Ptr (Errbuf'Unchecked_Access, False);

followed by:

Device := pcap_lookupdev(Errbuf_ptr);

Also note that this can result in Device being a null pointer, which will cause an error in the following:

Ada.Text_IO.Put_Line(Value(Device));

so better check, like this:

if Device = Null_Ptr then

Put_Line ("Null device: " & Value (Errbuf_Ptr));

else

Put_Line ("Found device: " & Value (Device));

end if;

HTH

--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
.



Relevant Pages