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

Reply via email to