Bug 241287
| Summary: | Calling sprintf/printf from Ada segfaults on x86_64 | ||
|---|---|---|---|
| Product: | [Fedora] Fedora | Reporter: | Orion Poplawski <orion> |
| Component: | gcc | Assignee: | Jakub Jelinek <jakub> |
| Status: | CLOSED NOTABUG | QA Contact: | |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | rawhide | ||
| Target Milestone: | --- | ||
| Target Release: | --- | ||
| Hardware: | x86_64 | ||
| OS: | Linux | ||
| Whiteboard: | |||
| 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: | --- | Target Upstream Version: | |
| Embargoed: | |||
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.
Thanks for the explanation Jakub - much appreciated. |
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.