[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]

"Perl_newSVpvf("%lld")" is broken



hv@crypt.org wrote:
:David Landgren <david@landgren.net> wrote:
::This Fortnight on perl5-porters - 28 September-12 October 2008
:[...]
::"Perl_newSVpvf("%lld")" is broken
::
::   One other item that fell out of the Y2038+ code was that, on 32-bit
::   platforms, "printf("%lld\n", 2**32)" gives a result of -1. Michael and
::   admitted to being terrified by the code and hoped someone else could
::   dig down through it and figure out where the problem lay.
::
::     quad wrangle
::     http://xrl.us/oudxw
:
:The problem is combo-ifdefs. First we get this:
:
:        case 'l':
:#if defined(HAS_QUAD) || defined(HAS_LONG_DOUBLE)
:            if (*(q + 1) == 'l') {      /* lld, llf */
:                intsize = 'q';
:                q += 2; 
:                break;
:             }
:#endif
:
:and then we get this (for the %d case):
:                default:        iv = tiv; break;
:#ifdef HAS_QUAD
:                case 'q':       iv = (Quad_t)tiv; break;
:#endif
:
:So when HAS_LONG_DOUBLE but not HAS_QUAD, we set intsize='q', but then
:silently go to the default (%d) case at the point we consume it.

Patch below (over blead@34775) should do the job. I'm not sure how to test
it, since results will be conditional on HAS_QUAD, but existing tests are
not broken by the patch.

:(It is also arguable that "%lld" isn't the most useful output, but if that
:is changed thought should be given to making the analogous change for %llf.)

I didn't change that.

Hugo
--- sv.c.old	2008-11-07 22:37:34.000000000 +0000
+++ sv.c	2008-11-08 12:52:17.000000000 +0000
@@ -9557,8 +9557,11 @@
 		case 'l':	iv = va_arg(*args, long); break;
 		case 'V':	iv = va_arg(*args, IV); break;
 		default:	iv = va_arg(*args, int); break;
+		case 'q':
 #ifdef HAS_QUAD
-		case 'q':	iv = va_arg(*args, Quad_t); break;
+				iv = va_arg(*args, Quad_t); break;
+#else
+				goto unknown;
 #endif
 		}
 	    }
@@ -9569,8 +9572,11 @@
 		case 'l':	iv = (long)tiv; break;
 		case 'V':
 		default:	iv = tiv; break;
+		case 'q':
 #ifdef HAS_QUAD
-		case 'q':	iv = (Quad_t)tiv; break;
+				iv = (Quad_t)tiv; break;
+#else
+				goto unknown;
 #endif
 		}
 	    }
@@ -9642,8 +9648,11 @@
 		case 'l':  uv = va_arg(*args, unsigned long); break;
 		case 'V':  uv = va_arg(*args, UV); break;
 		default:   uv = va_arg(*args, unsigned); break;
+		case 'q':
 #ifdef HAS_QUAD
-		case 'q':  uv = va_arg(*args, Uquad_t); break;
+			   uv = va_arg(*args, Uquad_t); break;
+#else
+			   goto unknown;
 #endif
 		}
 	    }
@@ -9654,8 +9663,11 @@
 		case 'l':	uv = (unsigned long)tuv; break;
 		case 'V':
 		default:	uv = tuv; break;
+		case 'q':
 #ifdef HAS_QUAD
-		case 'q':	uv = (Uquad_t)tuv; break;
+				uv = (Uquad_t)tuv; break;
+#else
+				goto unknown;
 #endif
 		}
 	    }
@@ -9941,8 +9953,11 @@
 		default:	*(va_arg(*args, int*)) = i; break;
 		case 'l':	*(va_arg(*args, long*)) = i; break;
 		case 'V':	*(va_arg(*args, IV*)) = i; break;
+		case 'q':
 #ifdef HAS_QUAD
-		case 'q':	*(va_arg(*args, Quad_t*)) = i; break;
+				*(va_arg(*args, Quad_t*)) = i; break;
+#else
+				goto unknown;
 #endif
 		}
 	    }


Follow-Ups from:
Marcus Holland-Moritz <mhx-perl@gmx.net>

[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]