comp.lang.ada
 help / color / mirror / Atom feed
* Question on interface Ada to C
@ 2004-05-25 21:00 James Alan Farrell
  2004-05-25 21:30 ` Dale Stanbrough
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: James Alan Farrell @ 2004-05-25 21:00 UTC (permalink / raw)


Hello all,
I've inherited a project that is half written in C and half in Ada.
I'm finding a lot of code  like that below (this is psuedocode and I
do not know that it will compile.  It gives the idea of what is going
without revealing company proprietary information)

The procedure is called by C.  It passes back a pointer to list, which
the C code uses to read data from list.

It seems to me that this is not safe because of the possibility that
the memory that holding the data will "go away" (be deallocated,
removed from the stack or whatever happens in this situation).

My boss at first thought this was good code but when he took a second
look he wasn't so sure.  So he's asked me to investigate.  What
exactly happens with the memory used by list in this situation?

We're using GNAT, but I don't think that's an issue -- I would think
this code would behave (or misbehave) the same no matter what
compiler.

Thanks,
James Alan Farrell
GrammaTech.

 type stuff is integer; -- just for example

 type List_Type is array(Integer range <>) of stuff;
 
 package MyPointers is 
              new System.Address_To_Access_Conversions(List_Type);
 subtype List_Pointer is MyPointers.Object_Pointer;

 procedure MyProc
     (Items     : in out List_Pointer;
      Nitems    : in out Integer) is

      List : List_Type := function_that_returns_a_list;

   begin
      Nitems := List'Length;
      Items  := MyPointers.To_Pointer(List'Address);
   end;



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Question on interface Ada to C
  2004-05-25 21:00 Question on interface Ada to C James Alan Farrell
@ 2004-05-25 21:30 ` Dale Stanbrough
  2004-05-25 21:38 ` Simon Wright
  2004-05-26  7:34 ` Martin Krischik
  2 siblings, 0 replies; 7+ messages in thread
From: Dale Stanbrough @ 2004-05-25 21:30 UTC (permalink / raw)


James Alan Farrell <anonymous@anonymous.com> wrote:


> Thanks,
> James Alan Farrell
> GrammaTech.
> 
>  type stuff is integer; -- just for example
> 
>  type List_Type is array(Integer range <>) of stuff;
>  
>  package MyPointers is 
>               new System.Address_To_Access_Conversions(List_Type);
>  subtype List_Pointer is MyPointers.Object_Pointer;
> 
>  procedure MyProc
>      (Items     : in out List_Pointer;
>       Nitems    : in out Integer) is
> 
>       List : List_Type := function_that_returns_a_list;
> 
>    begin
>       Nitems := List'Length;
>       Items  := MyPointers.To_Pointer(List'Address);
>    end;

You are right in thinking it is not good code.

The variable List is allocated on the stack/secondary head, and should
go away when the procedure ends. The pointer to it will no longer
be valid once you return from this procedure.


Better to have function_that_returns_a_list be
   function_that_returns_a_pointer_to_a_list

and return that....


      type List_Type_Access is access all List_Type;
      -- declare this type where it is visible to your
      -- other function.


      List_Ptr :+ list_type_access := function_that_returns_a_pointer...
   begin
      Nitems := List.all'Length;
      Items  := MyPointers.To_Pointer(List.all(1)'Address);
   end;


there's probably other stuff you should look at in the Interfaces.C.*
package family - there will be a better way than this.


Dale

-- 
dstanbro@spam.o.matic.bigpond.net.au



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Question on interface Ada to C
  2004-05-25 21:00 Question on interface Ada to C James Alan Farrell
  2004-05-25 21:30 ` Dale Stanbrough
@ 2004-05-25 21:38 ` Simon Wright
  2004-05-26 10:23   ` Dale Stanbrough
  2004-05-26 13:05   ` James Alan Farrell
  2004-05-26  7:34 ` Martin Krischik
  2 siblings, 2 replies; 7+ messages in thread
From: Simon Wright @ 2004-05-25 21:38 UTC (permalink / raw)


James Alan Farrell <anonymous@anonymous.com> writes:

>  type stuff is integer; -- just for example
> 
>  type List_Type is array(Integer range <>) of stuff;
>  
>  package MyPointers is 
>               new System.Address_To_Access_Conversions(List_Type);
>  subtype List_Pointer is MyPointers.Object_Pointer;
> 
>  procedure MyProc
>      (Items     : in out List_Pointer;
>       Nitems    : in out Integer) is
> 
>       List : List_Type := function_that_returns_a_list;

List is on the stack

> 
>    begin
>       Nitems := List'Length;
>       Items  := MyPointers.To_Pointer(List'Address);
>    end;

List has gone away!

I think you're going to need to allocate the particular array and get
the C code to free it (well, that's dangerous, perhaps you should
supply an Ada subprogram to actually do the freeing so as to be sure
the right storage pool is used; or perhaps you could import malloc?)

And I don't think C will understand a List_Pointer, because List_Type
is unconstrained so any concrete List may have bounds with it. There's
no reason to suppose that List'Address is the same as List
(List'First)'Address. The C is expecting effectively a System.Address,
so make your Items parameter a System.Address (why is it in out, BTW?)

One "trick" is to declare a local subtype which is constrained by the
actual bounds.

  List : List_Type := function_that_returns_a_list;
  type actual_list_type is list_type (list'range); -- or suchlike
  -- instantiate System.Address_To_Access_Conversions for actual_list_type
  function malloc (n : natural) return system.address;
  pragma import (c, malloc, "malloc");
begin
  Items := malloc (actual_list_type'max_size_in_storage_elements);
  -- copy the contents of List using the System.Address_To_Access_Conversions
  -- instantiation above

Good grief, that looks complicated, I dare say I've missed something
simple ..

-- 
Simon Wright                               100% Ada, no bugs.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Question on interface Ada to C
  2004-05-25 21:00 Question on interface Ada to C James Alan Farrell
  2004-05-25 21:30 ` Dale Stanbrough
  2004-05-25 21:38 ` Simon Wright
@ 2004-05-26  7:34 ` Martin Krischik
  2 siblings, 0 replies; 7+ messages in thread
From: Martin Krischik @ 2004-05-26  7:34 UTC (permalink / raw)


James Alan Farrell wrote:

> Hello all,

> I've inherited a project that is half written in C and Ada.

Nothing wrong with that. You should carfully read Annex B. Currently I do a
lot of Ada / C mixed programming as well. It works quite well.

> My boss at first thought this was good code but when he took a second
> look he wasn't so sure.  So he's asked me to investigate.  What
> exactly happens with the memory used by list in this situation?

The code is indeed not very good.

> We're using GNAT, but I don't think that's an issue -- I would think
> this code would behave (or misbehave) the same no matter what
> compiler.

That depends if you use GNAT with gcc's own C or GNAT with some other C. 

> Thanks,
> James Alan Farrell
> GrammaTech.
> 
>  type stuff is integer; -- just for example
> 
>  type List_Type is array(Integer range <>) of stuff;
>  
>  package MyPointers is
>               new System.Address_To_Access_Conversions(List_Type);
>  subtype List_Pointer is MyPointers.Object_Pointer;
> 
>  procedure MyProc
>      (Items     : in out List_Pointer;
>       Nitems    : in out Integer) is
> 
>       List : List_Type := function_that_returns_a_list;
> 
>    begin
>       Nitems := List'Length;
>       Items  := MyPointers.To_Pointer(List'Address);
>    end;

List will be short lived after MyProc ends. Also list is indefinite - C has
no conzept of indefinite.

You should return a record like this (Example for Character):

----------------------------------------------------------------------------

   --
   --  C/Ada String Type
   --
   type C_Array
   is array
      (Natural range <>)
   of aliased
      Character;

----------------------------------------------------------------------------

   package C_Pointers
   is new
      Interfaces.C.Pointers (
         Index              => Natural,
         Element            => Character,
         Element_Array      => C_Array,
         Default_Terminator => Character'First);

----------------------------------------------------------------------------

   type C_String
   is record
      Data : C_Pointers.Pointer;
      Size : Interfaces.C.size_t;
   end record;

With GNAT you can use function as well. Returning a record from Ada to C
work OK.

C_String.Data should be allocated and freed with malloc. See:

http://cvs.sourceforge.net/viewcvs.py/adacl/CUnicode/Include/c-generic_strings.adb?rev=1.5&view=auto

If you use GNAT only then you can import malloc directly.

With Regards

Martin

-- 
mailto://krischik@users.sourceforge.net
http://www.ada.krischik.com




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Question on interface Ada to C
  2004-05-25 21:38 ` Simon Wright
@ 2004-05-26 10:23   ` Dale Stanbrough
  2004-05-26 13:05   ` James Alan Farrell
  1 sibling, 0 replies; 7+ messages in thread
From: Dale Stanbrough @ 2004-05-26 10:23 UTC (permalink / raw)


Simon Wright <simon@pushface.org> wrote:

> And I don't think C will understand a List_Pointer, because List_Type
> is unconstrained so any concrete List may have bounds with it. There's
> no reason to suppose that List'Address is the same as List
> (List'First)'Address. 


Ada83 was silent on this issue but Ada95 now mandates  this
behaviour.

So 

   List (List'First)'Address

will give you the address of the first item, not a descriptor.



Dale

-- 
dstanbro@spam.o.matic.bigpond.net.au



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Question on interface Ada to C
  2004-05-25 21:38 ` Simon Wright
  2004-05-26 10:23   ` Dale Stanbrough
@ 2004-05-26 13:05   ` James Alan Farrell
  2004-05-26 16:01     ` Martin Krischik
  1 sibling, 1 reply; 7+ messages in thread
From: James Alan Farrell @ 2004-05-26 13:05 UTC (permalink / raw)


Thank you for all the answers.

Why is it in out?  The quick answer is that is how it was done in the
code I inherited. 

 From what I understand, this was done to allow C to use a pointer
argument.  That does not match my understanding of how Ada works, but
I am new to Interfaces.C and do not have a good understanding of how
that works.

James Alan Farrell
GrammaTech


On 25 May 2004 22:38:07 +0100, Simon Wright <simon@pushface.org>
wrote:

>James Alan Farrell <anonymous@anonymous.com> writes:
>
>>  type stuff is integer; -- just for example
>> 
>>  type List_Type is array(Integer range <>) of stuff;
>>  
>>  package MyPointers is 
>>               new System.Address_To_Access_Conversions(List_Type);
>>  subtype List_Pointer is MyPointers.Object_Pointer;
>> 
>>  procedure MyProc
>>      (Items     : in out List_Pointer;
>>       Nitems    : in out Integer) is
>> 
>>       List : List_Type := function_that_returns_a_list;
>
>List is on the stack
>
>> 
>>    begin
>>       Nitems := List'Length;
>>       Items  := MyPointers.To_Pointer(List'Address);
>>    end;
>
>List has gone away!
>
>I think you're going to need to allocate the particular array and get
>the C code to free it (well, that's dangerous, perhaps you should
>supply an Ada subprogram to actually do the freeing so as to be sure
>the right storage pool is used; or perhaps you could import malloc?)
>
>And I don't think C will understand a List_Pointer, because List_Type
>is unconstrained so any concrete List may have bounds with it. There's
>no reason to suppose that List'Address is the same as List
>(List'First)'Address. The C is expecting effectively a System.Address,
>so make your Items parameter a System.Address (why is it in out, BTW?)
>
>One "trick" is to declare a local subtype which is constrained by the
>actual bounds.
>
>  List : List_Type := function_that_returns_a_list;
>  type actual_list_type is list_type (list'range); -- or suchlike
>  -- instantiate System.Address_To_Access_Conversions for actual_list_type
>  function malloc (n : natural) return system.address;
>  pragma import (c, malloc, "malloc");
>begin
>  Items := malloc (actual_list_type'max_size_in_storage_elements);
>  -- copy the contents of List using the System.Address_To_Access_Conversions
>  -- instantiation above
>
>Good grief, that looks complicated, I dare say I've missed something
>simple ..




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Question on interface Ada to C
  2004-05-26 13:05   ` James Alan Farrell
@ 2004-05-26 16:01     ` Martin Krischik
  0 siblings, 0 replies; 7+ messages in thread
From: Martin Krischik @ 2004-05-26 16:01 UTC (permalink / raw)


James Alan Farrell wrote:

> Thank you for all the answers.
> 
> Why is it in out?  The quick answer is that is how it was done in the
> code I inherited.
> 
>  From what I understand, this was done to allow C to use a pointer
> argument.  That does not match my understanding of how Ada works, but
> I am new to Interfaces.C and do not have a good understanding of how
> that works.

Your understanding is right of corse. "out" and "in out" both create call by
reference of convetion C is used. "in" on records is call by reference as
well. However, there is a convention C_Pass_By_Copy if you need fine
tuning.

With Regards

Martin

-- 
mailto://krischik@users.sourceforge.net
http://www.ada.krischik.com




^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2004-05-26 16:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-05-25 21:00 Question on interface Ada to C James Alan Farrell
2004-05-25 21:30 ` Dale Stanbrough
2004-05-25 21:38 ` Simon Wright
2004-05-26 10:23   ` Dale Stanbrough
2004-05-26 13:05   ` James Alan Farrell
2004-05-26 16:01     ` Martin Krischik
2004-05-26  7:34 ` Martin Krischik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox