songmaster has asked for the wisdom of the Perl Monks concerning the following question:
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().
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: XS on 64-bit: Warning from sv_vsetpvf call
by almut (Canon) on Jun 27, 2008 at 01:55 UTC | |
by songmaster (Beadle) on Jun 27, 2008 at 04:46 UTC | |
by Anonymous Monk on Jun 27, 2008 at 16:35 UTC |