Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Possible compiler bug with this simple program

69 views
Skip to first unread message

Jerry

unread,
Aug 28, 2008, 3:28:29 AM8/28/08
to
The following is a program which emulates the structure of a binding
to a bunch of C code (but there is no C code included here--it is all
Ada). This structure exhibits a behavior which I think might be a
compiler error but could be the result of incorrect declarations when
running on certain machines.

Specifically, the program compiles (with two warnings which are
expected and OK) and runs correctly on my machine, OS X 10.4.11
running GNAT 4.3.0 (32-bit PowerPC G4). However, on someone else's
box, a 64-bit Intel Duo running Debian lenny and GNAT 4.3.1-2, the
program compiles but bombs at runtime with

raised STORAGE_ERROR : stack overflow (or erroneous memory access)

reported.

However, on the Debian lenny machine, if the three lines with

--***

at the end of them are commented out (they relate to Pragma-C
conventions), the program compiles and runs correctly, printing out 10
lines of floats. (It also runs correctly on the OS X machine.)

Here is the program, stored in two files (damn the line wraps):

========== Begin program ==========

with
type_declaration,
Ada.Text_IO;
use
type_declaration,
Ada.Text_IO;

procedure x19a_temp is

procedure mapform19(n : Integer; x : in out Real_Vector); --***
pragma Convention(C, mapform19); --***

procedure mapform19(n : Integer; x : in out Real_Vector) is
begin
for i in 0 .. n - 1 loop
x(i) := Long_Float(i);
Put_Line(Long_Float'image(x(i)));
end loop;
end mapform19;

begin
plmap(mapform19'Unrestricted_Access);
end x19a_temp;

package type_declaration is

type Real_Vector is array (Integer range <>) of Long_Float;

type Map_Form_Function_Pointer_Type is access
procedure (Length_Of_x : Integer; x : in out Real_Vector);
pragma Convention(Convention => C,
Entity => Map_Form_Function_Pointer_Type); --***

procedure plmap(Map_Form_Function_Pointer :
Map_Form_Function_Pointer_Type);

end type_declaration;

========== End program ============


Now: Here are some integer declaration sizes for the OS X 32-bit
version and the Debian 64-bit version. I could provide more but these
should be more than sufficient if there is in fact a problem in this
area.

===== OS X 32-bit sizes =====
Integer bits is 32
Long_Integer bits is 32
Long_Long_Integer bits is 64
Long_Float bits is 64
In Interfaces.C, int bits is 32
In Interfaces.C, long bits is 32
In Interfaces.C, C_float bits is 32
In Interfaces.C, double bits is 64

===== Debian 64-bit sizes =====
Integer bits is 32
Long_Integer bits is 64
Long_Long_Integer bits is 64
Long_Float bits is 64
In Interfaces.C, int bits is 32
In Interfaces.C, long bits is 64
In Interfaces.C, C_float bits is 32
In Interfaces.C, double bits is 64


I'm inclined to think that there is a compiler problem that makes the
64-bit Debian version crash but am wondering if there could be a
problem with word lengths that causes the problem.


As a second problem, in the program above there is a loop line that
looks like this:

for i in 0 .. n - 1 loop

One would normally write this as

for i in x'range loop

but when this runs on the OS X box, it segfaults after printing about
187 lines of bogus floats. I don't know what happens on the Debian
box. However, if the -- *** lines are commented out, it runs OK on OS
X.

Comments?

Jerry

Ludovic Brenta

unread,
Aug 28, 2008, 3:56:36 AM8/28/08
to


Jerry wrote:
> The following is a program which emulates the structure of a binding
> to a bunch of C code (but there is no C code included here--it is all
> Ada). This structure exhibits a behavior which I think might be a
> compiler error but could be the result of incorrect declarations when
> running on certain machines.
>
> Specifically, the program compiles (with two warnings which are
> expected and OK) and runs correctly on my machine, OS X 10.4.11
> running GNAT 4.3.0 (32-bit PowerPC G4). However, on someone else's
> box, a 64-bit Intel Duo running Debian lenny and GNAT 4.3.1-2, the
> program compiles but bombs at runtime with
>
> raised STORAGE_ERROR : stack overflow (or erroneous memory access)
>
> reported.

I cannot test your program now but it seems to me that perhaps you
should specify the alignment of the arrays and Long_Floats. Also, it
might be a good idea to double-check that on the Intel Core 2, the
long floats are really 64 bits and not 80 bits wide. It could be that
the compiler got that wrong but I doubt it.

Also, have you tried to compare the assembly language emitted by the
compiler with and without pragma Convention? (try gnatmake -c -cargs -
S)

[...]


> As a second problem, in the program above there is a loop line that
> looks like this:
>
> for i in 0 .. n - 1 loop
>
> One would normally write this as
>
> for i in x'range loop
>
> but when this runs on the OS X box, it segfaults after printing about
> 187 lines of bogus floats. I don't know what happens on the Debian
> box. However, if the -- *** lines are commented out, it runs OK on OS
> X.

This is to be expected. With convention C, there is no array anymore;
instead the procedure receives a pointer to the first element of the
array, so it doesn't have any information about the range. That's why
it is necessary to pass the length of the array separately.

HTH

--
Ludovic Brenta.

Niklas Holsti

unread,
Aug 28, 2008, 4:03:43 AM8/28/08
to
Jerry wrote:
> The following is a program which emulates the structure of a binding
> to a bunch of C code (but there is no C code included here--it is all
> Ada). This structure exhibits a behavior which I think might be a
> compiler error but could be the result of incorrect declarations when
> running on certain machines.

I suspect that one problem is using the C convention to pass a
parameter that is of an unconstrained array type, see below.

> Specifically, the program compiles (with two warnings which are
> expected and OK) and runs correctly on my machine, OS X 10.4.11
> running GNAT 4.3.0 (32-bit PowerPC G4). However, on someone else's
> box, a 64-bit Intel Duo running Debian lenny and GNAT 4.3.1-2, the
> program compiles but bombs at runtime with
>
> raised STORAGE_ERROR : stack overflow (or erroneous memory access)
>
> reported.
>
> However, on the Debian lenny machine, if the three lines with
>
> --***
>
> at the end of them are commented out (they relate to Pragma-C
> conventions), the program compiles and runs correctly, printing out 10
> lines of floats. (It also runs correctly on the OS X machine.)
>
> Here is the program, stored in two files (damn the line wraps):
>

...


>
> procedure x19a_temp is
>
> procedure mapform19(n : Integer; x : in out Real_Vector); --***
> pragma Convention(C, mapform19); --***

> procedure mapform19(n : Integer; x : in out Real_Vector) is

...


>
>
> package type_declaration is
>
> type Real_Vector is array (Integer range <>) of Long_Float;

So Real_Vector is an unconstrained array type. According to RM
B.3(70), the C convention passes only a single pointer to the first
element of the array, so the 'Range attribute will not be available
to the subprogram.

> As a second problem, in the program above there is a loop line that
> looks like this:
>
> for i in 0 .. n - 1 loop
>
> One would normally write this as
>
> for i in x'range loop
>
> but when this runs on the OS X box, it segfaults after printing about
> 187 lines of bogus floats. I don't know what happens on the Debian
> box. However, if the -- *** lines are commented out, it runs OK on OS
> X.
>
> Comments?

My guess: the compiler implements convention C for the x parameter,
which means x'range is not available, but the code for the second
quoted for-loop tries to access x'range anyway -- boom! The
compiler should IMHO have rejected the use of x'range here, with an
error message.

Using the first form of the quoted loop may trigger the same
problem in the code that checks that x(i) has a valid index, i.

In fact, when an Ada subprogram has an unconstrained array
parameter with Convention C, it seems to me that the subprogram's
body cannot make any use of individual elements of the array,
because it doesn't know the index range, so the compiler should
reject any indexing of such an array parameter, as well as any
attempt to pass it on as a Convention Ada parameter.

Conclusion: Your program tries to do something that cannot possibly
work, but the compiler should have told you so.

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

Adam Beneschan

unread,
Aug 28, 2008, 11:54:15 AM8/28/08
to
On Aug 28, 1:03 am, Niklas Holsti <niklas.hol...@tidorum.invalid>
wrote:

> In fact, when an Ada subprogram has an unconstrained array
> parameter with Convention C, it seems to me that the subprogram's
> body cannot make any use of individual elements of the array,
> because it doesn't know the index range, so the compiler should
> reject any indexing of such an array parameter, as well as any
> attempt to pass it on as a Convention Ada parameter.

Yes, good point. For an unconstrained array parameter like X, the
compiler doesn't need to know what X'Last is in order to access
elements of the array---but it does need to know X'First. (X'Last is
needed for range checking but not for actually accessing elements.)
If you're using strictly Ada, with no Convention parameters or
anything, then when mapform19 is called, the caller somehow has to
make X'First and X'Last available to the routine, and then when X(I)
is accessed, the generated code must compute I - X'First, multiply
that by the element size, and add the result to the address of X's
data. When mapform19 is called from a C routine, nothing will be
passed in for X'First, but mapform19 will still try to subtract
something from I, and what value it will subtract is quite random---
could be zero, could be some other garbage value.

I agree that the compiler should have rejected this. But it might
work to declare Real_Vector as a constrained array:

type Real_Vector is array (0 .. Integer'Last) of Long_Float;

Now the compiler will know that X'First is 0 and, hopefully, behave
correctly.

-- Adam

Adam Beneschan

unread,
Aug 28, 2008, 11:56:12 AM8/28/08
to
On Aug 28, 8:54 am, Adam Beneschan <a...@irvine.com> wrote:

> I agree that the compiler should have rejected this. But it might
> work to declare Real_Vector as a constrained array:
>
> type Real_Vector is array (0 .. Integer'Last) of Long_Float;

Or, perhaps, declare a subtype:

subtype Constrained_Real_Vector is Real_Vector (0 ..
Integer'Last);

and use the subtype as the parameter type in mapform19 and your access-
to-procedure type.

-- Adam

Randy Brukardt

unread,
Aug 28, 2008, 5:01:35 PM8/28/08
to
"Niklas Holsti" <niklas...@tidorum.invalid> wrote in message
news:48b65b3b$0$25384$4f79...@news.tdc.fi...
...

> In fact, when an Ada subprogram has an unconstrained array parameter with
> Convention C, it seems to me that the subprogram's body cannot make any
> use of individual elements of the array, because it doesn't know the index
> range, so the compiler should reject any indexing of such an array
> parameter, as well as any attempt to pass it on as a Convention Ada
> parameter.

This is the subject of AI05-0002-1. (It was carried over from the Ada 95.)
[Now, I have to go look this one up because I don't remember anything about
what we decided...] Ah, yes:

"We do not require support for C convention interfacing pragmas for
unconstrained
array objects, unconstrained array function results, and most unconstrained
array parameters."

In particular, "An implementation need not support ... an Export or
Convention pragma applied to a subprogram which has a parameter of an
unconstrained array subtype;". The wording goes on to include unconstrained
array objects and function results as well.

Note that an implementation *can* support this if it wants; some
implementations do implement this with various meanings (Tucker reported
that their compiler gives the array maximum bounds) and it was thought to be
bad to break user programs that depend on such behaviors. But if it does
support it, it ought to do something sensible (raising random exceptions
doesn't count). (Also note that it is required to support pragma Import in
this case, as C doesn't care about the bounds and they can just be dropped.)

> Conclusion: Your program tries to do something that cannot possibly work,
> but the compiler should have told you so.

Well, not necessarily (see Tucker's implementation, for instance). But
either it should do something defined *or* reject it at compile-time.
(Janus/Ada would have rejected the Convention pragma.) In any case, it is
not required to support this in any useful way, and, as it is not portable,
it should be avoided.

Randy.


Jerry

unread,
Aug 28, 2008, 5:08:42 PM8/28/08
to
On Aug 28, 12:56 am, Ludovic Brenta <ludo...@ludovic-brenta.org>
wrote:

> I cannot test your program now but it seems to me that perhaps you
> should specify the alignment of the arrays and Long_Floats. Also, it
> might be a good idea to double-check that on the Intel Core 2, the
> long floats are really 64 bits and not 80 bits wide. It could be that
> the compiler got that wrong but I doubt it.
>
And that would look something like this?

for Long_Float'Alignment use 64;
for Real_Vector'Alignment use ???;

Jerry

Jerry

unread,
Aug 28, 2008, 5:16:21 PM8/28/08
to


Thanks, everybody, for the comments.

As for the second problem ( in 0 .. n - 1 loop versus for i in x'range
loop), my main concern (since I have a workaround--the first form) is
that the compiler allows the second form at all. It looks like a
situation where a simple syntactically correct program bombs.

Also, I should have mentioned that the two warnings that are emitted
at compile time as a result of passing the unconstrained array via C
conventions are this:

x19a_temp.adb:10:38: warning: type of argument "mapform19.x" is
unconstrained array
x19a_temp.adb:10:38: warning: foreign caller must pass bounds
explicitly

I get this pair of warnings in other places where I do some callbacks
to C so I expected to see it here, as well, and I'm fine with that.


Also, I apologize for not including the body part of type_declarations
which looks like this:

========== Begin body part ==========

package body type_declaration is

procedure plmap(Map_Form_Function_Pointer :
Map_Form_Function_Pointer_Type) is
xx : Real_Vector(0 .. 9);
begin
Map_Form_Function_Pointer(xx'length, xx);
end plmap;

end type_declaration;

========== End body part ==========

Does the declaration of xx here as a constrained array change anyone's
comments about array boundaries not being known later?

Jerry

unread,
Aug 28, 2008, 5:29:41 PM8/28/08
to
On Aug 28, 2:01 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
> "Niklas Holsti" <niklas.hol...@tidorum.invalid> wrote in message

Thanks, Randy. This is useful.

Superficially, in my situation, it appears that GNAT 4.3.0 on OS X PPC
supports it and GNAT 4.3.1-2 on Debian lenny on Intel duo does not
support it. I suppose there could be an element of dumb luck of GNAT
is not supposed to support it and it just happens to work on OS X. On
the other hand, if GNAT is supposed to support it then the Debian/
Intel version is broken.

The fact that warnings are issued (see my other post today where I
actually list the two warnings) indicates that passing unconstrained
arrays is supported but the caller had better not screw things up by
trying to access outside bounds (which my example handles correctly).
If that is the case, it looks like the Debian/Intel box is broken.

And yes, portability isn't good, according to your report.

FWIW, in the _real_ application that I am working on, plmap is written
in C (and accessed from my binding by an Import).

Do AdaCore people have any comments on this?

Jerry

Niklas Holsti

unread,
Aug 29, 2008, 3:41:17 AM8/29/08
to
...

>>As a second problem, in the program above there is a loop line that
>>looks like this:
>>
>> for i in 0 .. n - 1 loop
>>
>>One would normally write this as
>>
>> for i in x'range loop
>>
>>but when this runs on the OS X box, it segfaults after printing about
>>187 lines of bogus floats. I don't know what happens on the Debian
>>box. However, if the -- *** lines are commented out, it runs OK on OS
>>X.
>>
>>Comments?
>>
>>Jerry
>
>
>
> Thanks, everybody, for the comments.
>
> As for the second problem ( in 0 .. n - 1 loop versus for i in x'range
> loop), my main concern (since I have a workaround--the first form) ...

Even if the workaround using "in 0 .. n - 1" works on a given
compiler and machine, according to Randy this depends on
non-standard (ie. generally unportable) features of the compiler.

For example, Randy mentioned that Tucker's compiler would give the
x-array "maximum bounds", which in this case seems to mean
Integer'First .. Integer'Last, and so x(0) would lie somewhere far
beyond the actual array in memory.

For "in 0 .. n-1" to work on Tucker's compiler, you should probably
declare Real_Vector using Natural indices instead of Integer
indices, to make the "maximum bounds" be 0 .. Natural'Last.

> Also, I should have mentioned that the two warnings that are emitted
> at compile time as a result of passing the unconstrained array via C
> conventions are this:
>
> x19a_temp.adb:10:38: warning: type of argument "mapform19.x" is
> unconstrained array
> x19a_temp.adb:10:38: warning: foreign caller must pass bounds
> explicitly
>
> I get this pair of warnings in other places where I do some callbacks
> to C so I expected to see it here, as well, and I'm fine with that.

In C code there is no problem, as all arrays start at index 0.
(Which, of course, leads to other problems, but they are on the
design level :-)

> Also, I apologize for not including the body part of type_declarations
> which looks like this:
>
> ========== Begin body part ==========
>
> package body type_declaration is
>
> procedure plmap(Map_Form_Function_Pointer :
> Map_Form_Function_Pointer_Type) is
> xx : Real_Vector(0 .. 9);
> begin
> Map_Form_Function_Pointer(xx'length, xx);
> end plmap;
>
> end type_declaration;
>
> ========== End body part ==========
>
> Does the declaration of xx here as a constrained array change anyone's
> comments about array boundaries not being known later?

Not for me. Although the "xx" *object* is constrained, the *type*
is still unconstrained. This is the point: Convention C means that
the actual index range of "xx", although known at the point of
call, is not passed to Map_Form_Function_Pointer.all.

If I understand Randy's explanation correctly, it does not even
help to pass the index range explicitly (instead of passing just
the length, as in your code), because the compiler invents some
index range of its own for accessing the Convention C
unconstrained-array parameter within the Ada body of the
subprogram. For this code to work, you must just know what this
invented index-range is, in your compiler.

Ludovic Brenta

unread,
Aug 29, 2008, 4:39:56 PM8/29/08
to

Yes. In addition, these might help:

for Real_Vector'Component_Size use 64;
for Real_Vector'Alignment use 64;
pragma Pack (Real_Vector);

I'm actually puzzled as to why the program appears to work on 32-bit
platforms. I would expect a Storage_Error when accessing X (0) since,
per your declaration, X'First = Integer'First = -2**31, so X (0) is
probably way past the end of the array. The first thing I would try
is using Natural instead of Integer as the array index subtype. If
that fails, try specifying the 'Alignment and 'Component_Size. If
that still fails, look at the assembly code emitted on amd64.

I just received http://bugs.debian.org/497067, BTW.

--
Ludovic Brenta.

Jerry

unread,
Aug 29, 2008, 5:20:20 PM8/29/08
to
On Aug 29, 1:39 pm, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
> I'm actually puzzled as to why the program appears to work on 32-bit
> platforms. I would expect a Storage_Error when accessing X (0) since,
> per your declaration, X'First = Integer'First = -2**31, so X (0) is
> probably way past the end of the array.  The first thing I would try
> is using Natural instead of Integer as the array index subtype.  If
> that fails, try specifying the 'Alignment and 'Component_Size.  If
> that still fails, look at the assembly code emitted on amd64.
>
> I just receivedhttp://bugs.debian.org/497067, BTW.
>
> --
> Ludovic Brenta.

Thanks, Ludovic. I'll try these things and report back.

The bug report that you reference is (obviously) from the person who
initially noticed the problem on his 64-bit machine.

In his post he asks for others to try the simple example (which is a
linked tarball from the bug page that you listed) to collect more
evidence that the problem is only on 64-bit machines and not 32-bit
machines.

Here is the tarball link that might work from here:
http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=10;filename=simple_test_case.tar.gz;att=1;bug=497067

Jerry

Jerry

unread,
Aug 29, 2008, 5:31:56 PM8/29/08
to
On Aug 29, 2:20 pm, Jerry <lancebo...@qwest.net> wrote:
>
> Thanks, Ludovic. I'll try these things and report back.
>
> Jerry

Actually, I don't have access to a 64-bit crahsing machine so trying
these things is difficult, involving e-mailing test programs to
someone who does have such a machine.

Jerry

Randy Brukardt

unread,
Aug 29, 2008, 8:50:40 PM8/29/08
to
"Niklas Holsti" <niklas...@tidorum.invalid> wrote in message
news:48b7a778$0$23608$4f79...@news.tdc.fi...
...

> If I understand Randy's explanation correctly, it does not even help to
> pass the index range explicitly (instead of passing just the length, as in
> your code), because the compiler invents some index range of its own for
> accessing the Convention C unconstrained-array parameter within the Ada
> body of the subprogram. For this code to work, you must just know what
> this invented index-range is, in your compiler.

That is correct. For Ada, the passed in object must have some bounds, and
the compiler either invents them (hopefully documented somewhere), or
preferably, rejects the representation clause in the first place. I believe
early drafts of this AI required rejection, but there was enough concern
with compatibility that that was weakened in the final version. In any case,
this sort of thing is not portable in any way; you have to figure out what a
particular compiler does in order to use it at all.

The OP should keep in mind that an appropriate bug fix for GNAT is to reject
this example, so it's not clear to me that there is much value to pushing
for a bug fix here. The code should be fixed to avoid unconstrained array
parameters and results unless there is no chance that it will ever be used
on a different Ada compiler (including a newer version of GNAT, which could
change how this is handled).

Randy.


Randy Brukardt

unread,
Aug 29, 2008, 9:00:54 PM8/29/08
to
"Jerry" <lance...@qwest.net> wrote in message
news:97b1150b-cb8f-4972...@x16g2000prn.googlegroups.com...
...

>FWIW, in the _real_ application that I am working on, plmap is written
>in C (and accessed from my binding by an Import).

Interestingly, that's completely different. That *should* work on all Ada
compilers (note that the wording specifically excludes unconstrained
parameters for pragma Import).

This example program is unportable garbage, unfortunately, because of
AI05-0002-1, and also because of B.1(38.1/2) (the "buyer beware" clause:
there is no requirement that an Ada program actually work as expected if you
force its conventions to another language (like C).

Admittedly, this is a bit strange. In this case, C works fine as the
receiver of such a call because it has no need to know the bounds of the
array passed. (And if it does, they're going to be passed explicitly.) But
Ada does need to know those bounds, and you can't even pass them explicitly
because the Ada compiler will have to assume something for the lower bound
in order to generate indexing operations (and that may be different than
what you intended).

The net effect is that the example program doesn't prove anything useful. It
would need to import an actual C subprogram in order to be a useful test.

Randy.


Jerry

unread,
Aug 30, 2008, 12:47:57 AM8/30/08
to
On Aug 29, 6:00 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
> "Jerry" <lancebo...@qwest.net> wrote in message

OK--this clears things up for me. And possibly validates the reason I
wrote the _real_ application the way that I did, thinking that C
arrays always starts from 0 so passing the length along as a separate
parameter should work.

But it looks like in testing (and posting) an all-Ada example I
muddied the situation--or worse--used a completely different example
from what my original code was.

I'll see if I can make another example where plmap is a simple program
in C that is Import-ed and see if it bombs on a 64-bit computer.

Jerry

Jerry

unread,
Sep 1, 2008, 7:19:40 AM9/1/08
to
On Aug 29, 9:47 pm, Jerry <lancebo...@qwest.net> wrote:
> On Aug 29, 6:00 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
> > "Jerry" <lancebo...@qwest.net> wrote in message
>
> > >FWIW, in the _real_ application that I am working on, plmap is written
> > >in C (and accessed from my binding by an Import).
>
> > Interestingly, that's completely different. That *should* work on all Ada
> > compilers (note that the wording specifically excludes unconstrained
> > parameters for pragma Import).
<snip>
> >                                          Randy.

>
> I'll see if I can make another example where plmap is a simple program
> in C that is Import-ed and see if it bombs on a 64-bit computer.
>
> Jerry

I've changed the simple example so that plmap is implemented in C.

The results are the same as with the all-Ada version: It runs OK on my
OS X 10.4.11 machine, PPC, Ada 4.3, but my colleague reports that it
crashes on his 64-bit machine which I believe is still the 64-bit
Intel Duo running Debian lenny and GNAT 4.3.1-2. The crash looks the
same as before:

raised STORAGE_ERROR : stack overflow (or erroneous memory access)

The example as either a zip or tarball which includes the very short
code files and a three-line bash script can be downloaded from my site
here:

http://public.me.com/oscarruitt

or directly here:

http://public.me.com/oscarruitt/simple_test_case_with_c.zip
http://idisk.mac.com/oscarruitt-Public/simple_test_case_with_c.zip

(Let me know if these don't work.)

And here is the code directly:


-- x19a_temp.adb

with
type_declaration,
Ada.Text_IO;
use
type_declaration,
Ada.Text_IO;

procedure x19a_temp is

procedure mapform19(n : Integer; x : in out Real_Vector);

pragma Convention(C, mapform19);

procedure mapform19(n : Integer; x : in out Real_Vector) is

begin


for i in 0 .. n - 1 loop

x(i) := Long_Float(i);
Put_Line(Long_Float'image(x(i)));
end loop;
end mapform19;

begin
plmap(mapform19'Unrestricted_Access);
end x19a_temp;

-- type_declaration.ads

package type_declaration is

type Real_Vector is array (Integer range <>) of Long_Float;

type Map_Form_Function_Pointer_Type is access


procedure (Length_Of_x : Integer; x : in out Real_Vector);
pragma Convention(Convention => C, Entity =>
Map_Form_Function_Pointer_Type);

procedure plmap(Map_Form_Function_Pointer :
Map_Form_Function_Pointer_Type);
pragma Import(C, plmap, "plmap");

end type_declaration;

/* plplot.h */

#include <stdint.h>
void plmap( void (*mapform)(int32_t, double *));

/* plmap.c */

#include "plplot.h"
void plmap( void (*mapform)(int32_t, double *) )
{
int32_t n;
double xx[10];
n = 10;
(*mapform)(n, xx);
}


# Compile and run with these lines:

gcc -c plmap.c
gnatmake x19a_temp.adb -largs plmap.o
./x19a_temp


Thanks once again.

Jerry

Santiago Urueña

unread,
Sep 2, 2008, 6:10:36 PM9/2/08
to
> And that would look something like this?
>
> for Long_Float'Alignment use 64;
> for Real_Vector'Alignment use ???;
>
Note that 'Size is specified in _bits_ but 'Alignment is in _bytes_
(well, in storage units), so I assume that you really mean:

for Long_Float'Size use 64; -- bits
for Long_Float'Alignment use 8; -- bytes

Cheers,

--
Santiago Urueña-Pascual <sur...@gmail.com>

Jerry

unread,
Sep 3, 2008, 12:22:34 AM9/3/08
to
On Sep 1, 4:19 am, Jerry <lancebo...@qwest.net> wrote:
> On Aug 29, 9:47 pm, Jerry <lancebo...@qwest.net> wrote:
>
> > On Aug 29, 6:00 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
> > > "Jerry" <lancebo...@qwest.net> wrote in message
>
> > > >FWIW, in the _real_ application that I am working on, plmap is written
> > > >in C (and accessed from my binding by an Import).
>
> > > Interestingly, that's completely different. That *should* work on all Ada
> > > compilers (note that the wording specifically excludes unconstrained
> > > parameters for pragma Import).
>    <snip>
> > >                                          Randy.
>
> > I'll see if I can make another example where plmap is a simple program
> > in C that is Import-ed and see if it bombs on a 64-bit computer.
>
> > Jerry
>
> I've changed the simple example so that plmap is implemented in C.
>
There haven't been any responses about the above post with mixed Ada-C
code from this list but I have reports from the other developers on my
project that it also runs OK on 32-bit systems but hangs on 64-bit
systems.

Unless somebody has further comments in a few days about why this
isn't a bug, I'm going to report it as such.

Jerry

Adam Beneschan

unread,
Sep 3, 2008, 10:20:33 AM9/3/08
to

Several of us have pointed out that it's a bad idea to use an
unconstrained array type (i.e. Real_Vector) as a parameter to an
imported routine (or a routine with convention C), but the above code
still did it.

-- Adam

Jerry

unread,
Sep 3, 2008, 8:22:02 PM9/3/08
to
On Sep 3, 7:20 am, Adam Beneschan <a...@irvine.com> wrote:
>
> Several of us have pointed out that it's a bad idea to use an
> unconstrained array type (i.e. Real_Vector) as a parameter to an
> imported routine (or a routine with convention C), but the above code
> still did it.
>
>                               -- Adam

In about a hundred cases in this same binding project, I have passed
an unconstrained array (and its length) as a parameter to an Imported
C subprogram without consequence--no warnings, no errors, no hangs--on
several kinds of machines (32-bit and 64-bit). This seems to be
allowed by ARM B.3.70: "An Ada parameter of an array type with
component type T, of any mode, is passed as a t* argument to a C
function, where t is the C type corresponding to the Ada type T."
There is no restriction on unconstrained array types.

The reason that I posted the modified code (mixed Ada and C) is that
Randy's post indicated that it should work.

In one instance (of the "hundred"), I "rename" one of these Imported C
subprograms (it has two unconstrained arrays and their length as
parameters). At the point of the "rename," GNAT generates two
warnings, "foreign caller must pass bounds explicitly," and "type of
argument "plfill.y" is unconstrained array." (plfill is the procedure
name and y is one of the unconstrained arrays. A similar pair of
warnings is generated for the other passed unconstrained array.) The
purpose for renaming the procedure, which is originally declared as an
Import with C conventions in another package (without warnings), is to
allow the user to pass it as a callback to another Imported C
subprogram. This works without problems.

The difference between the two cases ([1] described above, herein, and
[2] the code in mixed Ada and C that I posted earlier), is that in
[1], both the called procedure and the callback procedure are written
in C, and the in problematic code [2], the called subprogram is in C
(plmap) but the callback (mapform19) is written in Ada, with C
conventions.

In a third scenario in the binding project [3], Ada successfully calls
an Imported procedure written in C and passes a callback written in
Ada with C conventions; this closely resembles the problematic code
[2] except that in [3], the callback function is passed with 'Access
and in [2] it is passed with 'Unrestricted_Access. Also, [3] doesn't
pass an unconstrained array. (I don't see how to make [2] work with
'access without requiring the user to put the user-written callback
into the binding package.)

Jerry

Adam Beneschan

unread,
Sep 3, 2008, 9:18:56 PM9/3/08
to
On Sep 3, 5:22 pm, Jerry <lancebo...@qwest.net> wrote:
> On Sep 3, 7:20 am, Adam Beneschan <a...@irvine.com> wrote:
>
>
>
> > Several of us have pointed out that it's a bad idea to use an
> > unconstrained array type (i.e. Real_Vector) as a parameter to an
> > imported routine (or a routine with convention C), but the above code
> > still did it.
>
> > -- Adam
>
> In about a hundred cases in this same binding project, I have passed
> an unconstrained array (and its length) as a parameter to an Imported
> C subprogram without consequence--no warnings, no errors, no hangs--on
> several kinds of machines (32-bit and 64-bit). This seems to be
> allowed by ARM B.3.70: "An Ada parameter of an array type with
> component type T, of any mode, is passed as a t* argument to a C
> function, where t is the C type corresponding to the Ada type T."
> There is no restriction on unconstrained array types.

This talks about passing an unconstrained array parameter *from* an
Ada routine *to* a C function. You're doing more than that---you're
having the C function pass the unconstrained array parameter back *to*
an Ada routine, which the manual says nothing about.


> The reason that I posted the modified code (mixed Ada and C) is that
> Randy's post indicated that it should work.

I think there must be a misunderstanding. In one of his posts he
seemed to imply that it should work to pass an unconstrained array
parameter to a C routine on all Ada compilers, but he then referred to
the program as "unportable garbage". In another post he said that
either the Ada compiler should document what should happen when an
unconstrained array parameter is passed from C to Ada and implement it
that way consistently (e.g. it should just decree that the lower bound
is 0 and document it that way---but that's just one possible way of
handling it), or reject the program. GNAT apparently doesn't do
either so it's defective. The bug in GNAT, I believe, is that it
compiles your Ada program in the first place---just my opinion.


> In one instance (of the "hundred"), I "rename" one of these Imported C
> subprograms (it has two unconstrained arrays and their length as
> parameters). At the point of the "rename," GNAT generates two
> warnings, "foreign caller must pass bounds explicitly," and "type of
> argument "plfill.y" is unconstrained array." (plfill is the procedure
> name and y is one of the unconstrained arrays. A similar pair of
> warnings is generated for the other passed unconstrained array.) The
> purpose for renaming the procedure, which is originally declared as an
> Import with C conventions in another package (without warnings), is to
> allow the user to pass it as a callback to another Imported C
> subprogram. This works without problems.
>
> The difference between the two cases ([1] described above, herein, and
> [2] the code in mixed Ada and C that I posted earlier), is that in
> [1], both the called procedure and the callback procedure are written
> in C, and the in problematic code [2], the called subprogram is in C
> (plmap) but the callback (mapform19) is written in Ada, with C
> conventions.

Yup, this is not surprising at all to me. And if you go back and
reread my earlier post, I believe I explained pretty thoroughly why
this is happening, and also gave you a solution. Don't use an
unconstrained array type in your callback routine. Period. You can
use unconstrained arrays when calling C routines from Ada; but if
you're going to call Ada routines from C, don't.

-- Adam


Jeffrey R. Carter

unread,
Sep 3, 2008, 9:31:36 PM9/3/08
to
Jerry wrote:
>
> In about a hundred cases in this same binding project, I have passed
> an unconstrained array (and its length) as a parameter to an Imported
> C subprogram without consequence--no warnings, no errors, no hangs--on
> several kinds of machines (32-bit and 64-bit). This seems to be
> allowed by ARM B.3.70: "An Ada parameter of an array type with
> component type T, of any mode, is passed as a t* argument to a C
> function, where t is the C type corresponding to the Ada type T."
> There is no restriction on unconstrained array types.

Yes, but you're passing a pointer to an Ada convention-C subprogram to a C
function, and C is calling that subprogram. The subprogram has a an
unconstrained array parameter. This says nothing about what happens when C calls
Ada.

Ada needs to know what the lower bound of this array parameter is, and
apparently your compiler is getting it wrong. Using a constrained array type
with a lower bound of zero and an upper bound as large or larger than can occur
would be the best choice for this situation.

--
Jeff Carter
"I fart in your general direction."
Monty Python & the Holy Grail
05

Randy Brukardt

unread,
Sep 3, 2008, 11:53:45 PM9/3/08
to
"Adam Beneschan" <ad...@irvine.com> wrote in message
news:90006a35-e933-40f1...@s20g2000prd.googlegroups.com...
...

>> The difference between the two cases ([1] described above, herein, and
>> [2] the code in mixed Ada and C that I posted earlier), is that in
>> [1], both the called procedure and the callback procedure are written
>> in C, and the in problematic code [2], the called subprogram is in C
>> (plmap) but the callback (mapform19) is written in Ada, with C
>> conventions.
>
> Yup, this is not surprising at all to me. And if you go back and
> reread my earlier post, I believe I explained pretty thoroughly why
> this is happening, and also gave you a solution. Don't use an
> unconstrained array type in your callback routine. Period. You can
> use unconstrained arrays when calling C routines from Ada; but if
> you're going to call Ada routines from C, don't.

Right. It is *only* OK to use an unconstrained array parameter in a
subprogram that has pragma Import. It is *not* OK in any other context for C
(objects, subprograms with Convention or Export pragmas, function returns of
any kind). Your program is still using pragma Convention and you are still
having C call Ada with an unconstrained parameter. You can't do that
portably.

I may have not looked carefully enough at your original program; I presumed
that reason you were using pragma Convention was so that you could write the
routine in Ada, and that it would be replaced by pragma Import in the real
program. If that was wrong, I probably mislead you.

Randy.


Adam Beneschan

unread,
Sep 4, 2008, 10:35:18 AM9/4/08
to
On Sep 3, 6:31 pm, "Jeffrey R. Carter"
<spam.jrcarter....@spam.acm.org> wrote:

> Ada needs to know what the lower bound of this array parameter is, and
> apparently your compiler is getting it wrong.

One other thing that probably ought to be mentioned: It's possible
that the compiler is trying to determine the lower bound by looking at
some memory location where it expects the lower bound to be, but in
reality (since the Ada routine is being called from C) contains a
random value previously used for something else. My experience is
that memory locations with random values contain zero a high
percentage of the time, so it would make sense that the program would
happen to work on some platforms, or on some targets. If I understood
the original post correctly, the program seemed to be working on some
platforms but not others, and it could well be because of this random
factor. It doesn't mean the compiler or the program were correct on
those platforms.


> Using a constrained array type

or subtype, I think.


> with a lower bound of zero and an upper bound as large or larger than can occur
> would be the best choice for this situation.

-- Adam

Jacob Sparre Andersen

unread,
Sep 4, 2008, 10:42:46 AM9/4/08
to
[ calling an Ada function from C with an array argument ]

Isn't this a case, where package Interfaces.C.Pointers is appropriate
to use? (Despite the name, it seems mostly to be concerned with
C-style "arrays".)

Greetings,

Jacob
--
"Never trust a statistic you have not falsified yourself."

Simon Wright

unread,
Sep 4, 2008, 4:49:56 PM9/4/08
to
Jerry <lance...@qwest.net> writes:

> The difference between the two cases ([1] described above, herein, and
> [2] the code in mixed Ada and C that I posted earlier), is that in
> [1], both the called procedure and the callback procedure are written
> in C, and the in problematic code [2], the called subprogram is in C
> (plmap) but the callback (mapform19) is written in Ada, with C
> conventions.

Referring to [2], you also need to be careful (GNAT & VxWorks at least)
if the C calling thread isn't an Ada task; the Ada code expects the
VxWorks TCB to contain a pointer to auxiliary Ada RTS structures.

Call GNAT.Threads.Register_Thread (as early as possible in the called
Ada subprogram, I guess! before it needs the secondary stack, for
example)

Ludovic Brenta

unread,
Sep 5, 2008, 4:17:27 AM9/5/08
to
Jeff Carter writes:
> Ada needs to know what the lower bound of this array parameter is, and
> apparently your compiler is getting it wrong. Using a constrained array type
> with a lower bound of zero and an upper bound as large or larger than can occur
> would be the best choice for this situation.

I would actually use a local, constrained array type of exactly the
required length:

procedure Ada_Callback (Length : in Natural; Array_Address : in
System.Address);
pragma Convention (C, Ada_Callback);

procedure Ada_Callback (Length : in Natural; Array_Address : in
System.Address) is
type Constrained_Array_Subtype is array (1 .. Length) of
Long_Float;
X : Constrained_Array_Subtype;
for X'Address use Array_Address;
pragma Import (Ada, X); -- disable default initialization
begin
...
end Ada_Callback;

I know using System.Address may seem unholy at first sight but this
implementation is explicit about what it does -- dangerous things with
an address received from the unsafe "external world" outside the
control of the compiler.

Comments?

--
Ludovic Brenta.

Adam Beneschan

unread,
Sep 5, 2008, 11:56:24 AM9/5/08
to
On Sep 5, 1:17 am, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
> Jeff Carter writes:
> > Ada needs to know what the lower bound of this array parameter is, and
> > apparently your compiler is getting it wrong. Using a constrained array type
> > with a lower bound of zero and an upper bound as large or larger than can occur
> > would be the best choice for this situation.
>
> I would actually use a local, constrained array type of exactly the
> required length:
>
> procedure Ada_Callback (Length : in Natural; Array_Address : in
> System.Address);
> pragma Convention (C, Ada_Callback);
>
> procedure Ada_Callback (Length : in Natural; Array_Address : in
> System.Address) is
> type Constrained_Array_Subtype is array (1 .. Length) of
> Long_Float;

or array (0 .. Length - 1)...


> X : Constrained_Array_Subtype;
> for X'Address use Array_Address;
> pragma Import (Ada, X); -- disable default initialization
> begin
> ...
> end Ada_Callback;
>
> I know using System.Address may seem unholy at first sight but this
> implementation is explicit about what it does -- dangerous things with
> an address received from the unsafe "external world" outside the
> control of the compiler.
>
> Comments?

Doing it your way has a better chance of being portable. Earlier,
others and I have recommended using a constrained array subtype (with
a large upper bound) as a parameter, and I'd guess that will have the
desired effect on most compilers, but you never know---sometimes
compilers have unexpected ways of doing things. If you're sure that a
System.Address will look just like a C (void *) or (double *) type,
and will be passed in the same way, then using a System.Address
parameter will make pretty sure that things will work right.

-- Adam


Jeffrey R. Carter

unread,
Sep 5, 2008, 1:09:56 PM9/5/08
to
Ludovic Brenta wrote:
>
> I know using System.Address may seem unholy at first sight but this
> implementation is explicit about what it does -- dangerous things with
> an address received from the unsafe "external world" outside the
> control of the compiler.
>
> Comments?

There's no guarantee that a C pointer and Ada's System.Address are the same
thing. Of course, to be safe, you shouldn't use Integer, Long_Float, or any
other type not declared in Interfaces.C and its children, or otherwise declared
convention C. So really this should be something like

type Double_Ptr is access all Interfaces.C.Double;
pragma Convention (C, Double_Ptr);

procedure Ada_Callback (Length : Interfaces.C.Int; First_Component : Double_Ptr);
pragma Convention (C, Ada_Callback);

And then mess with pointer arithmetic (:

But a constrained array type is just as safe:

type C_List is array (Interfaces.C.Int range 0 .. Interfaces.C.Int'Last) of
aliased Interfaces.C.Double;
pragma Convention (C, C_List);

procedure Ada_Callback (Length : Interfaces.C.Int; List : C_List);
pragma Convention (C, Ada_Callback);

And much easier to use.

--
Jeff Carter
"You me on the head hitted."
Never Give a Sucker an Even Break
108

Jerry

unread,
Sep 5, 2008, 11:03:33 PM9/5/08
to
Thanks for all the help, everyone. I have a report back that the
program (both the simple example and the actual application) work
correctly on at least one of the formerly hanging machines. As some of
you suggested, the fix was to use a constrained array starting from 0
and making it long enough to handle any reasonable usage. Not
especially elegant, but good enough.

Jerry

0 new messages