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;
}