Package: grub Version: 0.97-29 Followup-For: Bug #315774
I ran into the same segfaults when I compiled grub using gcc 4.1. It turned out the handling (pointer arithmetics) of variable arguments in char_io.c goes bad due to optimization. I replaced it with va_arg macros and the segfaults went away.
--- a/stage2/char_io.c 2007-06-24 18:27:01.000000000 +0200 +++ b/stage2/char_io.c 2007-06-24 21:40:17.000000000 +0200 @@ -20,6 +20,7 @@ #include <shared.h> #include <term.h> +#include <stdarg.h> #ifdef SUPPORT_HERCULES # include <hercules.h> @@ -182,10 +183,10 @@ grub_putstr (const char *str) void grub_printf (const char *format,...) { - int *dataptr = (int *) &format; char c, str[16]; - - dataptr++; + va_list argp; + + va_start(argp,format); while ((c = *(format++)) != 0) { @@ -200,21 +201,22 @@ grub_printf (const char *format,...) case 'X': #endif case 'u': - *convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0; + *convert_to_ascii (str, c, va_arg(argp, unsigned long *)) = 0; grub_putstr (str); break; #ifndef STAGE1_5 case 'c': - grub_putchar ((*(dataptr++)) & 0xff); + grub_putchar ((char) va_arg(argp, char *) & 0xff); break; case 's': - grub_putstr ((char *) *(dataptr++)); + grub_putstr (va_arg(argp, char *)); break; #endif } } + va_end(argp); } #ifndef STAGE1_5 @@ -223,11 +225,11 @@ grub_sprintf (char *buffer, const char * { /* XXX hohmuth ugly hack -- should unify with printf() */ - int *dataptr = (int *) &format; char c, *ptr, str[16]; char *bp = buffer; + va_list argp; - dataptr++; + va_start(argp,format); while ((c = *format++) != 0) { @@ -237,7 +239,7 @@ grub_sprintf (char *buffer, const char * switch (c = *(format++)) { case 'd': case 'u': case 'x': - *convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0; + *convert_to_ascii (str, c, va_arg(argp, unsigned long *)) = 0; ptr = str; @@ -245,12 +247,11 @@ grub_sprintf (char *buffer, const char * *bp++ = *(ptr++); /* putchar(*(ptr++)); */ break; - case 'c': *bp++ = (*(dataptr++))&0xff; - /* putchar((*(dataptr++))&0xff); */ + case 'c': *bp++ = ((char) va_arg(argp, char *)) & 0xff; break; case 's': - ptr = (char *) (*(dataptr++)); + ptr = (char *) va_arg(argp, char *); while ((c = *ptr++) != 0) *bp++ = c; /* putchar(c); */ @@ -258,6 +259,7 @@ grub_sprintf (char *buffer, const char * } } + va_end(argp); *bp = 0; return bp - buffer; }