comp.lang.ada
 help / color / mirror / Atom feed
From: Adam Beneschan <adam@irvine.com>
Subject: Re: Calling Ada Procedure from C - how to handle a char ptr/array
Date: Fri, 18 Nov 2011 13:38:09 -0800 (PST)
Date: 2011-11-18T13:38:09-08:00	[thread overview]
Message-ID: <9a38b451-14d8-4449-97b8-7f040ea63498@h30g2000pro.googlegroups.com> (raw)
In-Reply-To: ae047ab1-1309-46ce-a66f-69053d4b46d9@a16g2000yqk.googlegroups.com

On Nov 18, 12:41 pm, awdorrin <awdor...@gmail.com> wrote:
> Tried reworking the code into a function that returns a char_array,
> but got a STORAGE_ERROR with a stack overflow/erroneous memory access.
>
> function Get_Label return Interfaces.C.Char_array is
>   Label : String(1..8);
> begin
>   Label(1..8) := "12345678";
>
>   return Interfaces.C.To_C(Label);
> end;
>
> From the source code for To_C(), it allocates the char array, so I'm
> not sure why this error would be raised...

I just tried a small test case (written entirely in Ada) that declared
this function just the way you wrote it, then called it.  I compiled
using GNAT.  It didn't raise anything.  Also, I don't see anything
wrong with the function.  So I suspect the problem isn't occurring in
this function; it's occurring somewhere else.

Are you calling Get_Label directly from C?  If so, how is it declared
in your C code?

I don't agree with Jeff's suggestion to use a function that returns a
Char_Array.  The reason is that Char_Array is defined as an
unconstrained array, and the language says that implementations don't
have to support applying the C convention to functions that return
unconstrained arrays.  When I try this (writing a source that defines
Get_Label as above, and applying Export(C) to it), GNAT gives a
warning "foreign convention function Get_Label should not return
unconstrained array".  Are you using GNAT?  If so, do you get the same
warning?  If so, that's a good indication that things aren't going to
work.  When an Ada function returns an unconstrained array, it has to
arrange to return the bounds as well as the array data, and how it
does that will vary from one implementation to another.  Our compiler,
for example, treats this kind of function as a procedure with an
implicit OUT parameter that points to a record that will contain the
data pointer and the bounds, which the caller will interpret as the
function result.  I don't know how GNAT handles it.  Regardless, it
will probably not be the way that a C program will expect, so you're
likely to get mismatched parameters or something else that could
easily lead to a bad memory access.

From the warning you described in your original post, and from my
experience, I don't think GNAT handles an *unconstrained* char_array
as an OUT parameter.  But there are a couple ways to get around this.
One is to declare your own constrained subtype:

   subtype constrained_char_array is Interfaces.C.Char_Array
(Interfaces.C.Size_T);

which declares a constrained array whose bounds are the entire range
of Size_T.  Of course, those won't be the actual bounds, but it will
make GNAT think those are the actual bounds so that it doesn't
complain about bounds not being passed in, and it doesn't try to check
indexes against some bogus bound and get a Constraint_Error.

   procedure Get_Text (s : out constrained_char_array) is
   ...
       s := Interfaces.C.To_C (Label);       -- WRONG

This is wrong, because it will try to assign to all of s from indexes
Size_T'First to Size_T'Last.  Remember, that's what it thinks the
bounds are.  (In your original attempt, it had no idea what the bounds
were, so assigning "s :=" couldn't have worked either.)  Since the C
code isn't going to pass any bound information to Get_Text, you have
to help it by telling it what index range you're setting:

       s(Size_T'First .. Size_T'First + Label'Length) :=
Interfaces.C.To_C (Label);

The length of the left-hand slice is Label'Length + 1, but that's what
you want because To_C will stick a NUL character on the end of the
string.  Of course, if the character array in your C code isn't large
enough to handle this result, you will be screwed, but that's par for
the course in C.  It might be better to have the C function pass in
the sizeof() of the array as an extra parameter, which is how it's
done in some of the Unix system calls.  Then the Ada code could check
to make sure that Label'Length + 1 <= [the Size parameter], or raise
Constraint_Error if not.

Another possibility is to use chars_ptr and Update in the
Interfaces.C.Strings package.  I'll let you look those up.

Hope this helps,

                               -- Adam



  reply	other threads:[~2011-11-18 21:45 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-18 19:40 Calling Ada Procedure from C - how to handle a char ptr/array awdorrin
2011-11-18 19:56 ` Jeffrey Carter
2011-11-18 20:19   ` awdorrin
2011-11-18 20:41     ` awdorrin
2011-11-18 21:38       ` Adam Beneschan [this message]
2011-11-18 22:32       ` Georg Bauhaus
2011-11-19  2:16 ` Adam Beneschan
2011-11-21 16:33   ` awdorrin
2011-11-22 13:20     ` awdorrin
2011-11-22 13:28       ` Simon Wright
replies disabled

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