I'm working on an XS interface to an external C library. My current code builds and works fine on 32-bit x86 Linux (Fedora Core 8, Perl 5.8.8) and on Solaris 10, but when I build it for 64-bit Linux (FC8 on x86_64) I get this compiler warning and the program segfaults when this routine is called:

Cap5.xs: In function ‘printf_handler’: Cap5.xs:1013: warning: passing argument 4 of ‘Perl_sv_vsetpvf’ from incompatible pointer type

The relevant lines of Cap5.xs are:

static int printf_handler(const char *format, va_list args) { SV *printf_str; dSP; ENTER; SAVETMPS; printf_str = NEWSV(0, strlen(format) + 32); sv_vsetpvf(printf_str, format, &args);

Line 1013 is the last one shown above.

Perl's proto.h file declares Perl_sv_vsetpvf as:

PERL_CALLCONV void Perl_sv_vsetpvf(pTHX_ SV* sv, const char* pat, va_list* args);

The final argument there is a va_list*, which is exactly what my code is giving it. I'm not sure it really should have been a va_list* given that vprintf et al. take a va_list, but that's what the header says and it works fine on the other systems.

Interestingly, if I drop the & and just pass args as the final argument the code seems to work fine on 64-bit Linux (although the compiler still warns), but then it segfaults on the other systems.

Any advice? I'm guessing this may be a bug in gcc and not really a Perl problem at all...

Update: It appears that taking the address of a va_list is non-conforming C, so Perl's API is broken. See slide 19 of this PDF slideshow for details. I looked in RT and only found one bug report from 2002 that could be about this issue; should I report it?

2nd Update: On amd64 (and apparently on PowerPC too) va_list is defined by the ABI as an array:

typedef struct unsigned int gp_offset; unsigned int fp_offset; void *overflow_arg_area; void *reg_save_area; } va_list[1];

Thus within printf_handler() the args variable is already a pointer to the structure. This explains why dropping the & works as I described in my original question. Unfortunately that's no use on other architectures though.

Using va_copy() (or its equivalent) to copy args into an auto variable allows me to take the address of the copy and pass that pointer into sv_vsetpvf().


In reply to XS on 64-bit: Warning from sv_vsetpvf call by songmaster

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.