On Mar 10, 2010, at 5:50 PM, William A. Rowe Jr. wrote:

> On 3/10/2010 4:45 PM, Hyrum K. Wright wrote:
>> 
>> Digging deeper, it appears to be an error in apr_vformatter() when parsing 
>> the format '%lld'.  I'm running the tests on Mac OS X where APR_OFF_FMT_T is 
>> defined as lld, so this format occurs frequently.  Consequently, I'm also 
>> seeing a failure in testfmt at line 63, where the parser is attempting to 
>> parse APR_OFF_FMT_T, but failing.  Can anybody else replicate this bug?
> 
> Yes, this function isn't maintained on Mac OS/X.  Which is something
> of a surprise, given the number of Mac fans around here!
> 
> The defintions are very clear, %d must handle an (int) sized object,
> %ld must handle a (long) sized object, and %lld must handle any
> long long int sized object.  Patches welcome.
> 
> I plan to patch win32 to accept %I64[ld] because long long type was added
> with VS 7.1, while %ll was not added until the more recent Visual Studio 8.
> I64d goes further back in time to 6.0 or prior, and is how we specified
> the format tag for APR_OFF_T_FMT etc.

Digging even further.  It appears that the parser is attempting to match 
APR_INT64_T_FMT first, which may be of variable size.  On OS X, this is defined 
as 'ld', but the parser mistakenly matches APR_OFF_T_FMT, which is defined as 
'lld' for this case.

Attached is a patch which adds another block which preemptively matches 
APR_OFF_T_FMT.  I've tested it on OS X and a 64-bit Linux system.

-Hyrum

Index: strings/apr_snprintf.c
===================================================================
--- strings/apr_snprintf.c      (revision 921388)
+++ strings/apr_snprintf.c      (working copy)
@@ -810,10 +810,23 @@ APR_DECLARE(int) apr_vformatter(int (*flush_func)(
                 adjust_precision = adjust_width = NO;
 
             /*
-             * Modifier check.  Note that if APR_INT64_T_FMT is "d",
-             * the first if condition is never true.
+             * Modifier check.  Note that if APR_OFF_T_FMT is "d",
+             * the first if condition is never true, and if APR_INT64_T_FMT
+             * is "d", the second if condition is never true.
              */
-            if ((sizeof(APR_INT64_T_FMT) == 4 &&
+            if ((sizeof(APR_OFF_T_FMT) == 4 &&
+                 fmt[0] == APR_OFF_T_FMT[0] &&
+                 fmt[1] == APR_OFF_T_FMT[1]) ||
+                (sizeof(APR_OFF_T_FMT) == 3 &&
+                 fmt[0] == APR_OFF_T_FMT[0]) ||
+                (sizeof(APR_OFF_T_FMT) > 4 &&
+                 strncmp(fmt, APR_OFF_T_FMT, 
+                         sizeof(APR_OFF_T_FMT) - 2) == 0)) {
+                /* Need to account for trailing 'd' and null in sizeof() */
+                var_type = IS_QUAD;
+                fmt += (sizeof(APR_OFF_T_FMT) - 2);
+            }
+            else if ((sizeof(APR_INT64_T_FMT) == 4 &&
                  fmt[0] == APR_INT64_T_FMT[0] &&
                  fmt[1] == APR_INT64_T_FMT[1]) ||
                 (sizeof(APR_INT64_T_FMT) == 3 &&

Reply via email to