Bug 241287 - Calling sprintf/printf from Ada segfaults on x86_64
Calling sprintf/printf from Ada segfaults on x86_64
Status: CLOSED NOTABUG
Product: Fedora
Classification: Fedora
Component: gcc (Show other bugs)
rawhide
x86_64 Linux
medium Severity medium
: ---
: ---
Assigned To: Jakub Jelinek
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2007-05-24 16:42 EDT by Orion Poplawski
Modified: 2007-11-30 17:12 EST (History)
0 users

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2007-05-24 17:12:34 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Orion Poplawski 2007-05-24 16:42:40 EDT
Description of problem:

(This is somewhat confusing because I *think* this must have worked on April 16
which is when I built plplot-5.7.3-2.fc7, and the test that fails should have
been run then, but the build logs appear to be gone.)

I'm afraid I know almost nothing about Ada.  This code is adapted from a PlPlot
example test case.  Perhaps there is an obvious programming error, but it seems
like the interface declaration is correct.

with
    Ada.Text_IO,
    Ada.Numerics,
    Ada.Numerics.Long_Elementary_Functions,
    Ada.Strings.Bounded,
    Interfaces.C,
    Interfaces.C.Pointers,
    System,
    Ada.Strings.Unbounded;
use
    Interfaces.C,
    Ada.Text_IO,
    Ada.Strings.Bounded,
    Ada.Strings.Unbounded,
    Ada.Numerics,
    Ada.Numerics.Long_Elementary_Functions;

procedure x12b is
    y0 : array (Integer range 0 .. 9) of Long_Float;
    procedure Printf( format : in char_array; variable: in Long_Float );
    pragma Import(C, Printf, "printf" );

    begin
       y0(0) := 5.0;
       y0(1) := 15.0;
       y0(2) := 12.0;
       y0(3) := 24.0;
       y0(4) := 28.0;
       y0(5) := 30.0;
       y0(6) := 20.0;
       y0(7) := 8.0;
       y0(8) := 12.0;
       y0(9) := 3.0;

       for i in y0'Range loop
          printf(To_C("%.0f"), y0(i));
          printf(To_C("%.0f"), Long_Float(1980 + i));
       end loop;

end x12b;

When compiled and run on a Fedora Linux x86_64 machine it segfaults (or hangs in
an endless loop of segfaults as shown by strace).  Runs fine on i686. 
Originally the code used sprintf:

    string : char_array(0 .. 20);
    y0 : array (Integer range 0 .. 9) of Long_Float;
    procedure Sprintf( buffer : out char_array; format : in char_array;
variable: in Long_Float );
    pragma Import(C, Sprintf, "sprintf" );

and:

          sprintf(string, To_C("%.0f"), y0(i));

and that also crashes.

This is with gcc-gnat-4.1.1-51.fc5 through gcc-gnat-4.1.2-12.  Tested on FC5/6/7.
Comment 1 Jakub Jelinek 2007-05-24 17:12:34 EDT
This is clearly invalid code.
procedure Printf( format : in char_array; variable: in Long_Float );
pragma Import(C, Printf, "printf" );
You are lying to the compiler, printf is not printf (const char *, double)
but printf (const char *, ...).  While on i386 these two happen to have the
same calling convention, on x86_64 they don't (vararg functions need to
additionally set %rax register to the number of used %xmm* argument).
With the incorrect declaration, %rax contains some random value and if it
is bigger than 7, the code to save %xmm0..%xmm[%rax-1] registers to stack
(see x86_64 ABI) will just jump either to a middle of some instruction or some
unrelated instruction.
Not sure if Ada allows you to specify a vararg function some way, if yes,
use it, if not, you can't call these functions directly, you'd need to write
a short wrapper function in C that will do that:
int printf_arg_double (const char *fmt, double d) { return printf (fmt, d); }
and call that from Ada instead.
Comment 2 Orion Poplawski 2007-05-24 17:14:25 EDT
Thanks for the explanation Jakub - much appreciated.

Note You need to log in before you can comment on or make changes to this bug.