Bug 241287 - Calling sprintf/printf from Ada segfaults on x86_64
Summary: Calling sprintf/printf from Ada segfaults on x86_64
Status: CLOSED NOTABUG
Alias: None
Product: Fedora
Classification: Fedora
Component: gcc   
(Show other bugs)
Version: rawhide
Hardware: x86_64 Linux
medium
medium
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact:
URL:
Whiteboard:
Keywords:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2007-05-24 20:42 UTC by Orion Poplawski
Modified: 2007-11-30 22:12 UTC (History)
0 users

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


Attachments (Terms of Use)

Description Orion Poplawski 2007-05-24 20:42:40 UTC
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 21:12:34 UTC
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 21:14:25 UTC
Thanks for the explanation Jakub - much appreciated.


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