Bug 991027 - JS_snprintf: Don't allocate a temporary buffer when handling %hs format-specifier. r=Waldo.
authorJason Orendorff <jorendorff@mozilla.com>
Fri, 25 Apr 2014 11:50:33 -0500
changeset 180604 0eb5fefd5ca84ce7185bddbf847197acc6f062ee
parent 180603 4e47286ce9b73b661b29ea24ff009e90b563dc19
child 180605 ac3d60d50ccd112fb7407c2229c086634d5a0b0c
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersWaldo
bugs991027
milestone31.0a1
Bug 991027 - JS_snprintf: Don't allocate a temporary buffer when handling %hs format-specifier. r=Waldo.
js/src/devtools/rootAnalysis/annotations.js
js/src/jsprf.cpp
js/src/jsprf.h
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -57,16 +57,17 @@ function indirectCallCannotGC(fullCaller
 
     return false;
 }
 
 // Ignore calls through functions pointers with these types
 var ignoreClasses = {
     "JSTracer" : true,
     "JSStringFinalizer" : true,
+    "SprintfState" : true,
     "SprintfStateStr" : true,
     "JSLocaleCallbacks" : true,
     "JSC::ExecutableAllocator" : true,
     "PRIOMethods": true,
     "XPCOMFunctions" : true, // I'm a little unsure of this one
     "_MD_IOVector" : true,
 };
 
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -1,75 +1,67 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
-** Portable safe sprintf code.
-**
-** Author: Kipp E.B. Hickman
-*/
+ * Portable safe sprintf code.
+ *
+ * Author: Kipp E.B. Hickman
+ */
 
 #include "jsprf.h"
 
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "jspubtd.h"
 #include "jsstr.h"
 #include "jsutil.h"
 
 using namespace js;
 
 /*
-** Note: on some platforms va_list is defined as an array,
-** and requires array notation.
-*/
+ * Note: on some platforms va_list is defined as an array,
+ * and requires array notation.
+ */
 #ifdef HAVE_VA_COPY
-#define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo,bar)
+#define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo, bar)
 #elif defined(HAVE_VA_LIST_AS_ARRAY)
 #define VARARGS_ASSIGN(foo, bar)        foo[0] = bar[0]
 #else
 #define VARARGS_ASSIGN(foo, bar)        (foo) = (bar)
 #endif
 
-/*
-** WARNING: This code may *NOT* call JS_LOG (because JS_LOG calls it)
-*/
-
-/*
-** XXX This needs to be internationalized!
-*/
-
-typedef struct SprintfStateStr SprintfState;
-
-struct SprintfStateStr {
-    int (*stuff)(SprintfState *ss, const char *sp, uint32_t len);
+struct SprintfState
+{
+    int (*stuff)(SprintfState *ss, const char *sp, size_t len);
 
     char *base;
     char *cur;
-    uint32_t maxlen;
+    size_t maxlen;
 
     int (*func)(void *arg, const char *sp, uint32_t len);
     void *arg;
 };
 
 /*
-** Numbered Arguement State
-*/
-struct NumArgState{
-    int     type;               /* type of the current ap                    */
-    va_list ap;                 /* point to the corresponding position on ap */
+ * Numbered Argument State
+ */
+struct NumArgState
+{
+    int type;       // type of the current ap
+    va_list ap;     // point to the corresponding position on ap
 };
 
-#define NAS_DEFAULT_NUM 20  /* default number of NumberedArgumentState array */
+const size_t NAS_DEFAULT_NUM = 20;  // default number of NumberedArgumentState array
 
 
 #define TYPE_INT16      0
 #define TYPE_UINT16     1
 #define TYPE_INTN       2
 #define TYPE_UINTN      3
 #define TYPE_INT32      4
 #define TYPE_UINT32     5
@@ -82,60 +74,84 @@ struct NumArgState{
 #define TYPE_UNKNOWN    20
 
 #define FLAG_LEFT       0x1
 #define FLAG_SIGNED     0x2
 #define FLAG_SPACED     0x4
 #define FLAG_ZEROS      0x8
 #define FLAG_NEG        0x10
 
-/*
-** Fill into the buffer using the data in src
-*/
-static int fill2(SprintfState *ss, const char *src, int srclen, int width,
-                int flags)
+inline int
+generic_write(SprintfState *ss, const char *src, size_t srclen)
+{
+    return (*ss->stuff)(ss, src, srclen);
+}
+
+inline int
+generic_write(SprintfState *ss, const jschar *src, size_t srclen)
+{
+    const size_t CHUNK_SIZE = 64;
+    char chunk[CHUNK_SIZE];
+
+    int rv = 0;
+    size_t j = 0;
+    size_t i = 0;
+    while (i < srclen) {
+        // FIXME: truncates characters to 8 bits
+        chunk[j++] = char(src[i++]);
+
+        if (j == CHUNK_SIZE || i == srclen) {
+            rv = (*ss->stuff)(ss, chunk, j);
+            if (rv != 0)
+                return rv;
+            j = 0;
+        }
+    }
+    return 0;
+}
+
+// Fill into the buffer using the data in src
+template <typename Char>
+static int
+fill2(SprintfState *ss, const Char *src, int srclen, int width, int flags)
 {
     char space = ' ';
     int rv;
 
     width -= srclen;
-    if ((width > 0) && ((flags & FLAG_LEFT) == 0)) {    /* Right adjusting */
-        if (flags & FLAG_ZEROS) {
+    if (width > 0 && (flags & FLAG_LEFT) == 0) {    // Right adjusting
+        if (flags & FLAG_ZEROS)
             space = '0';
-        }
         while (--width >= 0) {
             rv = (*ss->stuff)(ss, &space, 1);
-            if (rv < 0) {
+            if (rv < 0)
                 return rv;
-            }
         }
     }
 
-    /* Copy out the source data */
-    rv = (*ss->stuff)(ss, src, uint32_t(srclen));
-    if (rv < 0) {
+    // Copy out the source data
+    rv = generic_write(ss, src, srclen);
+    if (rv < 0)
         return rv;
-    }
 
-    if ((width > 0) && ((flags & FLAG_LEFT) != 0)) {    /* Left adjusting */
+    if (width > 0 && (flags & FLAG_LEFT) != 0) {    // Left adjusting
         while (--width >= 0) {
             rv = (*ss->stuff)(ss, &space, 1);
-            if (rv < 0) {
+            if (rv < 0)
                 return rv;
-            }
         }
     }
     return 0;
 }
 
 /*
-** Fill a number. The order is: optional-sign zero-filling conversion-digits
-*/
-static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
-                  int prec, int type, int flags)
+ * Fill a number. The order is: optional-sign zero-filling conversion-digits
+ */
+static int
+fill_n(SprintfState *ss, const char *src, int srclen, int width, int prec, int type, int flags)
 {
     int zerowidth = 0;
     int precwidth = 0;
     int signwidth = 0;
     int leftspaces = 0;
     int rightspaces = 0;
     int cvtwidth;
     int rv;
@@ -152,36 +168,36 @@ static int fill_n(SprintfState *ss, cons
             sign = ' ';
             signwidth = 1;
         }
     }
     cvtwidth = signwidth + srclen;
 
     if (prec > 0) {
         if (prec > srclen) {
-            precwidth = prec - srclen;          /* Need zero filling */
+            precwidth = prec - srclen;          // Need zero filling
             cvtwidth += precwidth;
         }
     }
 
     if ((flags & FLAG_ZEROS) && (prec < 0)) {
         if (width > cvtwidth) {
-            zerowidth = width - cvtwidth;       /* Zero filling */
+            zerowidth = width - cvtwidth;       // Zero filling
             cvtwidth += zerowidth;
         }
     }
 
     if (flags & FLAG_LEFT) {
         if (width > cvtwidth) {
-            /* Space filling on the right (i.e. left adjusting) */
+            // Space filling on the right (i.e. left adjusting)
             rightspaces = width - cvtwidth;
         }
     } else {
         if (width > cvtwidth) {
-            /* Space filling on the left (i.e. right adjusting) */
+            // Space filling on the left (i.e. right adjusting)
             leftspaces = width - cvtwidth;
         }
     }
     while (--leftspaces >= 0) {
         rv = (*ss->stuff)(ss, " ", 1);
         if (rv < 0) {
             return rv;
         }
@@ -212,72 +228,61 @@ static int fill_n(SprintfState *ss, cons
         rv = (*ss->stuff)(ss, " ", 1);
         if (rv < 0) {
             return rv;
         }
     }
     return 0;
 }
 
-/*
-** Convert a long into its printable form
-*/
+/* Convert a long into its printable form. */
 static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
                  int type, int flags, const char *hexp)
 {
     char cvtbuf[100];
     char *cvt;
     int digits;
 
-    /* according to the man page this needs to happen */
+    // according to the man page this needs to happen
     if ((prec == 0) && (num == 0)) {
         return 0;
     }
 
-    /*
-    ** Converting decimal is a little tricky. In the unsigned case we
-    ** need to stop when we hit 10 digits. In the signed case, we can
-    ** stop when the number is zero.
-    */
+    // Converting decimal is a little tricky. In the unsigned case we
+    // need to stop when we hit 10 digits. In the signed case, we can
+    // stop when the number is zero.
     cvt = cvtbuf + sizeof(cvtbuf);
     digits = 0;
     while (num) {
         int digit = (((unsigned long)num) % radix) & 0xF;
         *--cvt = hexp[digit];
         digits++;
         num = (long)(((unsigned long)num) / radix);
     }
     if (digits == 0) {
         *--cvt = '0';
         digits++;
     }
 
-    /*
-    ** Now that we have the number converted without its sign, deal with
-    ** the sign and zero padding.
-    */
+    // Now that we have the number converted without its sign, deal with
+    // the sign and zero padding.
     return fill_n(ss, cvt, digits, width, prec, type, flags);
 }
 
-/*
-** Convert a 64-bit integer into its printable form
-*/
+/* Convert a 64-bit integer into its printable form. */
 static int cvt_ll(SprintfState *ss, int64_t num, int width, int prec, int radix,
                   int type, int flags, const char *hexp)
 {
-    /* according to the man page this needs to happen */
-    if (prec == 0 && num == 0) {
+    // According to the man page, this needs to happen.
+    if (prec == 0 && num == 0)
         return 0;
-    }
 
-    /*
-    ** Converting decimal is a little tricky. In the unsigned case we
-    ** need to stop when we hit 10 digits. In the signed case, we can
-    ** stop when the number is zero.
-    */
+    // Converting decimal is a little tricky. In the unsigned case we
+    // need to stop when we hit 10 digits. In the signed case, we can
+    // stop when the number is zero.
     int64_t rad = int64_t(radix);
     char cvtbuf[100];
     char *cvt = cvtbuf + sizeof(cvtbuf);
     int digits = 0;
     while (num != 0) {
         int64_t quot = uint64_t(num) / rad;
         int64_t rem = uint64_t(num) % rad;
         int32_t digit = int32_t(rem);
@@ -285,378 +290,340 @@ static int cvt_ll(SprintfState *ss, int6
         digits++;
         num = quot;
     }
     if (digits == 0) {
         *--cvt = '0';
         digits++;
     }
 
-    /*
-    ** Now that we have the number converted without its sign, deal with
-    ** the sign and zero padding.
-    */
+    // Now that we have the number converted without its sign, deal with
+    // the sign and zero padding.
     return fill_n(ss, cvt, digits, width, prec, type, flags);
 }
 
 /*
-** Convert a double precision floating point number into its printable
-** form.
-**
-** XXX stop using sprintf to convert floating point
-*/
+ * Convert a double precision floating point number into its printable
+ * form.
+ *
+ * XXX stop using sprintf to convert floating point
+ */
 static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
 {
     char fin[20];
     char fout[300];
     int amount = fmt1 - fmt0;
 
     JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin)));
     if (amount >= (int)sizeof(fin)) {
-        /* Totally bogus % command to sprintf. Just ignore it */
+        // Totally bogus % command to sprintf. Just ignore it
         return 0;
     }
     js_memcpy(fin, fmt0, (size_t)amount);
     fin[amount] = 0;
 
-    /* Convert floating point using the native sprintf code */
+    // Convert floating point using the native sprintf code
 #ifdef DEBUG
     {
         const char *p = fin;
         while (*p) {
             JS_ASSERT(*p != 'L');
             p++;
         }
     }
 #endif
     sprintf(fout, fin, d);
 
-    /*
-    ** This assert will catch overflow's of fout, when building with
-    ** debugging on. At least this way we can track down the evil piece
-    ** of calling code and fix it!
-    */
+    // This assert will catch overflow's of fout, when building with
+    // debugging on. At least this way we can track down the evil piece
+    // of calling code and fix it!
     JS_ASSERT(strlen(fout) < sizeof(fout));
 
     return (*ss->stuff)(ss, fout, strlen(fout));
 }
 
+static inline const char *generic_null_str(const char *) { return "(null)"; }
+static inline const jschar *generic_null_str(const jschar *) { return MOZ_UTF16("(null)"); }
+
+static inline size_t generic_strlen(const char *s) { return strlen(s); }
+static inline size_t generic_strlen(const jschar *s) { return js_strlen(s); }
+
 /*
-** Convert a string into its printable form.  "width" is the output
-** width. "prec" is the maximum number of characters of "s" to output,
-** where -1 means until NUL.
-*/
-static int cvt_s(SprintfState *ss, const char *s, int width, int prec,
-                 int flags)
+ * Convert a string into its printable form.  "width" is the output
+ * width. "prec" is the maximum number of characters of "s" to output,
+ * where -1 means until NUL.
+ */
+template <typename Char>
+static int
+cvt_s(SprintfState *ss, const Char *s, int width, int prec, int flags)
 {
-    int slen;
-
     if (prec == 0)
         return 0;
-
-    /* Limit string length by precision value */
-    slen = s ? strlen(s) : 6;
-    if (prec > 0) {
-        if (prec < slen) {
-            slen = prec;
-        }
-    }
-
-    /* and away we go */
-    return fill2(ss, s ? s : "(null)", slen, width, flags);
-}
+    if (!s)
+        s = generic_null_str(s);
 
-static int
-cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec, int flags)
-{
-    int result;
-    /*
-     * Supply nullptr as the JSContext; errors are not reported,
-     * and js_malloc() is used to allocate the buffer.
-     */
-    if (ws) {
-        size_t wslen = js_strlen(ws);
-        char *latin1 = js_pod_malloc<char>(wslen + 1);
-        if (!latin1)
-            return -1; /* JSStuffFunc error indicator. */
-        for (size_t i = 0; i < wslen; ++i)
-            latin1[i] = (char)ws[i];
-        latin1[wslen] = '\0';
-        result = cvt_s(ss, latin1, width, prec, flags);
-        js_free(latin1);
-    } else {
-        result = cvt_s(ss, nullptr, width, prec, flags);
-    }
-    return result;
+    // Limit string length by precision value
+    int slen = int(generic_strlen(s));
+    if (0 < prec && prec < slen)
+        slen = prec;
+
+    // and away we go
+    return fill2(ss, s, slen, width, flags);
 }
 
 /*
-** BuildArgArray stands for Numbered Argument list Sprintf
-** for example,
-**      fmp = "%4$i, %2$d, %3s, %1d";
-** the number must start from 1, and no gap among them
-*/
-
-static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArgState* nasArray )
+ * BuildArgArray stands for Numbered Argument list Sprintf
+ * for example,
+ *      fmp = "%4$i, %2$d, %3s, %1d";
+ * the number must start from 1, and no gap among them
+ */
+static NumArgState *
+BuildArgArray(const char *fmt, va_list ap, int *rv, NumArgState *nasArray)
 {
-    int number = 0, cn = 0, i;
+    size_t number = 0, cn = 0, i;
     const char *p;
     char c;
-    struct NumArgState *nas;
+    NumArgState *nas;
 
 
-    /*
-    **  first pass:
-    **  detemine how many legal % I have got, then allocate space
-    */
+    // First pass:
+    // Detemine how many legal % I have got, then allocate space.
 
     p = fmt;
     *rv = 0;
     i = 0;
-    while( ( c = *p++ ) != 0 ){
-        if( c != '%' )
+    while ((c = *p++) != 0) {
+        if (c != '%')
             continue;
-        if( ( c = *p++ ) == '%' )       /* skip %% case */
+        if ((c = *p++) == '%')          // skip %% case
             continue;
 
-        while( c != 0 ){
-            if( c > '9' || c < '0' ){
-                if( c == '$' ){         /* numbered argument csae */
-                    if( i > 0 ){
+        while (c != 0) {
+            if (c > '9' || c < '0') {
+                if (c == '$') {         // numbered argument case
+                    if (i > 0) {
                         *rv = -1;
                         return nullptr;
                     }
                     number++;
-                } else {                /* non-numbered argument case */
-                    if( number > 0 ){
+                } else {                // non-numbered argument case
+                    if (number > 0) {
                         *rv = -1;
                         return nullptr;
                     }
                     i = 1;
                 }
                 break;
             }
 
             c = *p++;
         }
     }
 
-    if( number == 0 ){
+    if (number == 0)
         return nullptr;
-    }
 
-
-    if( number > NAS_DEFAULT_NUM ){
-        nas = (struct NumArgState*)js_malloc( number * sizeof( struct NumArgState ) );
-        if( !nas ){
+    if (number > NAS_DEFAULT_NUM) {
+        nas = (NumArgState *) js_malloc(number * sizeof(NumArgState));
+        if (!nas) {
             *rv = -1;
             return nullptr;
         }
     } else {
         nas = nasArray;
     }
 
-    for( i = 0; i < number; i++ ){
+    for (i = 0; i < number; i++)
         nas[i].type = TYPE_UNKNOWN;
-    }
 
 
-    /*
-    ** second pass:
-    ** set nas[].type
-    */
+    // Second pass:
+    // Set nas[].type.
 
     p = fmt;
-    while( ( c = *p++ ) != 0 ){
-        if( c != '%' )  continue;
-            c = *p++;
-        if( c == '%' )  continue;
+    while ((c = *p++) != 0) {
+        if (c != '%')
+            continue;
+        c = *p++;
+        if (c == '%')
+            continue;
 
         cn = 0;
-        while( c && c != '$' ){     /* should improve error check later */
+        while (c && c != '$') {     // should improve error check later
             cn = cn*10 + c - '0';
             c = *p++;
         }
 
-        if( !c || cn < 1 || cn > number ){
+        if (!c || cn < 1 || cn > number) {
             *rv = -1;
             break;
         }
 
-        /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
+        // nas[cn] starts from 0, and make sure nas[cn].type is not assigned.
         cn--;
-        if( nas[cn].type != TYPE_UNKNOWN )
+        if (nas[cn].type != TYPE_UNKNOWN)
             continue;
 
         c = *p++;
 
-        /* width */
+        // width
         if (c == '*') {
-            /* not supported feature, for the argument is not numbered */
+            // not supported feature, for the argument is not numbered
             *rv = -1;
             break;
         }
 
         while ((c >= '0') && (c <= '9')) {
             c = *p++;
         }
 
-        /* precision */
+        // precision
         if (c == '.') {
             c = *p++;
             if (c == '*') {
-                /* not supported feature, for the argument is not numbered */
+                // not supported feature, for the argument is not numbered
                 *rv = -1;
                 break;
             }
 
             while ((c >= '0') && (c <= '9')) {
                 c = *p++;
             }
         }
 
-        /* size */
+        // size
         nas[cn].type = TYPE_INTN;
         if (c == 'h') {
             nas[cn].type = TYPE_INT16;
             c = *p++;
         } else if (c == 'L') {
-            /* XXX not quite sure here */
+            // XXX not quite sure here
             nas[cn].type = TYPE_INT64;
             c = *p++;
         } else if (c == 'l') {
             nas[cn].type = TYPE_INT32;
             c = *p++;
             if (c == 'l') {
                 nas[cn].type = TYPE_INT64;
                 c = *p++;
             }
         }
 
-        /* format */
+        // format
         switch (c) {
         case 'd':
         case 'c':
         case 'i':
         case 'o':
         case 'u':
         case 'x':
         case 'X':
             break;
 
         case 'e':
         case 'f':
         case 'g':
-            nas[ cn ].type = TYPE_DOUBLE;
+            nas[cn].type = TYPE_DOUBLE;
             break;
 
         case 'p':
-            /* XXX should use cpp */
+            // XXX should use cpp
             if (sizeof(void *) == sizeof(int32_t)) {
-                nas[ cn ].type = TYPE_UINT32;
+                nas[cn].type = TYPE_UINT32;
             } else if (sizeof(void *) == sizeof(int64_t)) {
-                nas[ cn ].type = TYPE_UINT64;
+                nas[cn].type = TYPE_UINT64;
             } else if (sizeof(void *) == sizeof(int)) {
-                nas[ cn ].type = TYPE_UINTN;
+                nas[cn].type = TYPE_UINTN;
             } else {
-                nas[ cn ].type = TYPE_UNKNOWN;
+                nas[cn].type = TYPE_UNKNOWN;
             }
             break;
 
         case 'C':
         case 'S':
         case 'E':
         case 'G':
-            /* XXX not supported I suppose */
+            // XXX not supported I suppose
             JS_ASSERT(0);
-            nas[ cn ].type = TYPE_UNKNOWN;
+            nas[cn].type = TYPE_UNKNOWN;
             break;
 
         case 's':
-            nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
+            nas[cn].type = (nas[cn].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
             break;
 
         case 'n':
-            nas[ cn ].type = TYPE_INTSTR;
+            nas[cn].type = TYPE_INTSTR;
             break;
 
         default:
             JS_ASSERT(0);
-            nas[ cn ].type = TYPE_UNKNOWN;
+            nas[cn].type = TYPE_UNKNOWN;
             break;
         }
 
-        /* get a legal para. */
-        if( nas[ cn ].type == TYPE_UNKNOWN ){
+        // get a legal para.
+        if (nas[cn].type == TYPE_UNKNOWN) {
             *rv = -1;
             break;
         }
     }
 
 
-    /*
-    ** third pass
-    ** fill the nas[cn].ap
-    */
+    // Third pass:
+    // Fill nas[].ap.
 
-    if( *rv < 0 ){
-        if( nas != nasArray )
-            js_free( nas );
+    if (*rv < 0) {
+        if (nas != nasArray)
+            js_free(nas);
         return nullptr;
     }
 
     cn = 0;
-    while( cn < number ){
-        if( nas[cn].type == TYPE_UNKNOWN ){
+    while (cn < number) {
+        if (nas[cn].type == TYPE_UNKNOWN) {
             cn++;
             continue;
         }
 
         VARARGS_ASSIGN(nas[cn].ap, ap);
 
-        switch( nas[cn].type ){
+        switch (nas[cn].type) {
         case TYPE_INT16:
         case TYPE_UINT16:
         case TYPE_INTN:
-        case TYPE_UINTN:                (void)va_arg( ap, int );             break;
-
-        case TYPE_INT32:                (void)va_arg( ap, int32_t );            break;
-
-        case TYPE_UINT32:       (void)va_arg( ap, uint32_t );   break;
-
-        case TYPE_INT64:        (void)va_arg( ap, int64_t );            break;
-
-        case TYPE_UINT64:       (void)va_arg( ap, uint64_t );           break;
-
-        case TYPE_STRING:       (void)va_arg( ap, char* );              break;
-
-        case TYPE_WSTRING:      (void)va_arg( ap, jschar* );            break;
-
-        case TYPE_INTSTR:       (void)va_arg( ap, int* );            break;
-
-        case TYPE_DOUBLE:       (void)va_arg( ap, double );             break;
+        case TYPE_UINTN:        (void) va_arg(ap, int);         break;
+        case TYPE_INT32:        (void) va_arg(ap, int32_t);     break;
+        case TYPE_UINT32:       (void) va_arg(ap, uint32_t);    break;
+        case TYPE_INT64:        (void) va_arg(ap, int64_t);     break;
+        case TYPE_UINT64:       (void) va_arg(ap, uint64_t);    break;
+        case TYPE_STRING:       (void) va_arg(ap, char*);       break;
+        case TYPE_WSTRING:      (void) va_arg(ap, jschar*);     break;
+        case TYPE_INTSTR:       (void) va_arg(ap, int*);        break;
+        case TYPE_DOUBLE:       (void) va_arg(ap, double);      break;
 
         default:
-            if( nas != nasArray )
-                js_free( nas );
+            if (nas != nasArray)
+                js_free(nas);
             *rv = -1;
             return nullptr;
         }
 
         cn++;
     }
 
 
     return nas;
 }
 
 /*
-** The workhorse sprintf code.
-*/
-static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
+ * The workhorse sprintf code.
+ */
+static int
+dosprintf(SprintfState *ss, const char *fmt, va_list ap)
 {
     char c;
     int flags, width, prec, radix, type;
     union {
         char ch;
         jschar wch;
         int i;
         long l;
@@ -666,163 +633,157 @@ static int dosprintf(SprintfState *ss, c
         const jschar* ws;
         int *ip;
     } u;
     const char *fmt0;
     static const char hex[] = "0123456789abcdef";
     static const char HEX[] = "0123456789ABCDEF";
     const char *hexp;
     int rv, i;
-    struct NumArgState *nas = nullptr;
-    struct NumArgState nasArray[ NAS_DEFAULT_NUM ];
+    NumArgState *nas = nullptr;
+    NumArgState nasArray[NAS_DEFAULT_NUM];
     char pattern[20];
-    const char *dolPt = nullptr;  /* in "%4$.2f", dolPt will poiont to . */
+    const char *dolPt = nullptr;  // in "%4$.2f", dolPt will point to '.'
 
-    /*
-    ** build an argument array, IF the fmt is numbered argument
-    ** list style, to contain the Numbered Argument list pointers
-    */
+    // Build an argument array, IF the fmt is numbered argument
+    // list style, to contain the Numbered Argument list pointers.
 
-    nas = BuildArgArray( fmt, ap, &rv, nasArray );
-    if( rv < 0 ){
-        /* the fmt contains error Numbered Argument format, jliu@netscape.com */
+    nas = BuildArgArray(fmt, ap, &rv, nasArray);
+    if (rv < 0) {
+        // the fmt contains error Numbered Argument format, jliu@netscape.com
         JS_ASSERT(0);
         return rv;
     }
 
     while ((c = *fmt++) != 0) {
         if (c != '%') {
             rv = (*ss->stuff)(ss, fmt - 1, 1);
             if (rv < 0) {
                 return rv;
             }
             continue;
         }
         fmt0 = fmt - 1;
 
-        /*
-        ** Gobble up the % format string. Hopefully we have handled all
-        ** of the strange cases!
-        */
+        // Gobble up the % format string. Hopefully we have handled all
+        // of the strange cases!
         flags = 0;
         c = *fmt++;
         if (c == '%') {
-            /* quoting a % with %% */
+            // quoting a % with %%
             rv = (*ss->stuff)(ss, fmt - 1, 1);
             if (rv < 0) {
                 return rv;
             }
             continue;
         }
 
-        if( nas != nullptr ){
-            /* the fmt contains the Numbered Arguments feature */
+        if (nas != nullptr) {
+            // the fmt contains the Numbered Arguments feature
             i = 0;
-            while( c && c != '$' ){         /* should imporve error check later */
-                i = ( i * 10 ) + ( c - '0' );
+            while (c && c != '$') {         // should improve error check later
+                i = (i * 10) + (c - '0');
                 c = *fmt++;
             }
 
-            if( nas[i-1].type == TYPE_UNKNOWN ){
-                if( nas && ( nas != nasArray ) )
-                    js_free( nas );
+            if (nas[i-1].type == TYPE_UNKNOWN) {
+                if (nas && nas != nasArray)
+                    js_free(nas);
                 return -1;
             }
 
             ap = nas[i-1].ap;
             dolPt = fmt;
             c = *fmt++;
         }
 
-        /*
-         * Examine optional flags.  Note that we do not implement the
-         * '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
-         * somewhat ambiguous and not ideal, which is perhaps why
-         * the various sprintf() implementations are inconsistent
-         * on this feature.
-         */
+        // Examine optional flags.  Note that we do not implement the
+        // '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
+        // somewhat ambiguous and not ideal, which is perhaps why
+        // the various sprintf() implementations are inconsistent
+        // on this feature.
         while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
             if (c == '-') flags |= FLAG_LEFT;
             if (c == '+') flags |= FLAG_SIGNED;
             if (c == ' ') flags |= FLAG_SPACED;
             if (c == '0') flags |= FLAG_ZEROS;
             c = *fmt++;
         }
         if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
         if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
 
-        /* width */
+        // width
         if (c == '*') {
             c = *fmt++;
             width = va_arg(ap, int);
         } else {
             width = 0;
             while ((c >= '0') && (c <= '9')) {
                 width = (width * 10) + (c - '0');
                 c = *fmt++;
             }
         }
 
-        /* precision */
+        // precision
         prec = -1;
         if (c == '.') {
             c = *fmt++;
             if (c == '*') {
                 c = *fmt++;
                 prec = va_arg(ap, int);
             } else {
                 prec = 0;
                 while ((c >= '0') && (c <= '9')) {
                     prec = (prec * 10) + (c - '0');
                     c = *fmt++;
                 }
             }
         }
 
-        /* size */
+        // size
         type = TYPE_INTN;
         if (c == 'h') {
             type = TYPE_INT16;
             c = *fmt++;
         } else if (c == 'L') {
-            /* XXX not quite sure here */
+            // XXX not quite sure here
             type = TYPE_INT64;
             c = *fmt++;
         } else if (c == 'l') {
             type = TYPE_INT32;
             c = *fmt++;
             if (c == 'l') {
                 type = TYPE_INT64;
                 c = *fmt++;
             }
         }
 
-        /* format */
+        // format
         hexp = hex;
         switch (c) {
-          case 'd': case 'i':                   /* decimal/integer */
+          case 'd': case 'i':                   // decimal/integer
             radix = 10;
             goto fetch_and_convert;
 
-          case 'o':                             /* octal */
+          case 'o':                             // octal
             radix = 8;
             type |= 1;
             goto fetch_and_convert;
 
-          case 'u':                             /* unsigned decimal */
+          case 'u':                             // unsigned decimal
             radix = 10;
             type |= 1;
             goto fetch_and_convert;
 
-          case 'x':                             /* unsigned hex */
+          case 'x':                             // unsigned hex
             radix = 16;
             type |= 1;
             goto fetch_and_convert;
 
-          case 'X':                             /* unsigned HEX */
+          case 'X':                             // unsigned HEX
             radix = 16;
             hexp = HEX;
             type |= 1;
             goto fetch_and_convert;
 
           fetch_and_convert:
             switch (type) {
               case TYPE_INT16:
@@ -880,22 +841,22 @@ static int dosprintf(SprintfState *ss, c
             }
             break;
 
           case 'e':
           case 'E':
           case 'f':
           case 'g':
             u.d = va_arg(ap, double);
-            if( nas != nullptr ){
+            if (nas != nullptr) {
                 i = fmt - dolPt;
-                if( i < (int)sizeof( pattern ) ){
+                if (i < int(sizeof(pattern))) {
                     pattern[0] = '%';
-                    js_memcpy( &pattern[1], dolPt, (size_t)i );
-                    rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
+                    js_memcpy(&pattern[1], dolPt, size_t(i));
+                    rv = cvt_f(ss, u.d, pattern, &pattern[i + 1]);
                 }
             } else
                 rv = cvt_f(ss, u.d, fmt0, fmt);
 
             if (rv < 0) {
                 return rv;
             }
             break;
@@ -943,25 +904,25 @@ static int dosprintf(SprintfState *ss, c
             radix = 16;
             goto fetch_and_convert;
 
 #if 0
           case 'C':
           case 'S':
           case 'E':
           case 'G':
-            /* XXX not supported I suppose */
+            // XXX not supported I suppose
             JS_ASSERT(0);
             break;
 #endif
 
           case 's':
             if(type == TYPE_INT16) {
                 u.ws = va_arg(ap, const jschar*);
-                rv = cvt_ws(ss, u.ws, width, prec, flags);
+                rv = cvt_s(ss, u.ws, width, prec, flags);
             } else {
                 u.s = va_arg(ap, const char*);
                 rv = cvt_s(ss, u.s, width, prec, flags);
             }
             if (rv < 0) {
                 return rv;
             }
             break;
@@ -969,137 +930,102 @@ static int dosprintf(SprintfState *ss, c
           case 'n':
             u.ip = va_arg(ap, int*);
             if (u.ip) {
                 *u.ip = ss->cur - ss->base;
             }
             break;
 
           default:
-            /* Not a % token after all... skip it */
+            // Not a % token after all... skip it
 #if 0
             JS_ASSERT(0);
 #endif
             rv = (*ss->stuff)(ss, "%", 1);
             if (rv < 0) {
                 return rv;
             }
             rv = (*ss->stuff)(ss, fmt - 1, 1);
             if (rv < 0) {
                 return rv;
             }
         }
     }
 
-    /* Stuff trailing NUL */
+    // Stuff trailing NUL
     rv = (*ss->stuff)(ss, "\0", 1);
 
-    if( nas && ( nas != nasArray ) ){
-        js_free( nas );
-    }
+    if (nas && nas != nasArray)
+        js_free(nas);
 
     return rv;
 }
 
 /************************************************************************/
 
-static int FuncStuff(SprintfState *ss, const char *sp, uint32_t len)
-{
-    int rv;
-
-    rv = (*ss->func)(ss->arg, sp, len);
-    if (rv < 0) {
-        return rv;
-    }
-    ss->maxlen += len;
-    return 0;
-}
-
-JS_PUBLIC_API(uint32_t) JS_sxprintf(JSStuffFunc func, void *arg,
-                                    const char *fmt, ...)
-{
-    va_list ap;
-    int rv;
-
-    va_start(ap, fmt);
-    rv = JS_vsxprintf(func, arg, fmt, ap);
-    va_end(ap);
-    return rv;
-}
-
-JS_PUBLIC_API(uint32_t) JS_vsxprintf(JSStuffFunc func, void *arg,
-                                     const char *fmt, va_list ap)
-{
-    SprintfState ss;
-    int rv;
-
-    ss.stuff = FuncStuff;
-    ss.func = func;
-    ss.arg = arg;
-    ss.maxlen = 0;
-    rv = dosprintf(&ss, fmt, ap);
-    return (rv < 0) ? UINT32_MAX : ss.maxlen;
-}
-
 /*
-** Stuff routine that automatically grows the js_malloc'd output buffer
-** before it overflows.
-*/
-static int GrowStuff(SprintfState *ss, const char *sp, uint32_t len)
+ * Stuff routine that automatically grows the js_malloc'd output buffer
+ * before it overflows.
+ */
+static int
+GrowStuff(SprintfState *ss, const char *sp, size_t len)
 {
     ptrdiff_t off;
     char *newbase;
-    uint32_t newlen;
+    size_t newlen;
 
     off = ss->cur - ss->base;
     if (off + len >= ss->maxlen) {
         /* Grow the buffer */
         newlen = ss->maxlen + ((len > 32) ? len : 32);
-        newbase = (char*) js_realloc(ss->base, newlen);
+        newbase = static_cast<char *>(js_realloc(ss->base, newlen));
         if (!newbase) {
             /* Ran out of memory */
             return -1;
         }
         ss->base = newbase;
         ss->maxlen = newlen;
         ss->cur = ss->base + off;
     }
 
     /* Copy data */
     while (len) {
         --len;
         *ss->cur++ = *sp++;
     }
-    JS_ASSERT(uint32_t(ss->cur - ss->base) <= ss->maxlen);
+    MOZ_ASSERT(size_t(ss->cur - ss->base) <= ss->maxlen);
     return 0;
 }
 
 /*
-** sprintf into a js_malloc'd buffer
-*/
-JS_PUBLIC_API(char *) JS_smprintf(const char *fmt, ...)
+ * sprintf into a js_malloc'd buffer
+ */
+JS_PUBLIC_API(char *)
+JS_smprintf(const char *fmt, ...)
 {
     va_list ap;
     char *rv;
 
     va_start(ap, fmt);
     rv = JS_vsmprintf(fmt, ap);
     va_end(ap);
     return rv;
 }
 
 /*
-** Free memory allocated, for the caller, by JS_smprintf
-*/
-JS_PUBLIC_API(void) JS_smprintf_free(char *mem)
+ * Free memory allocated, for the caller, by JS_smprintf
+ */
+JS_PUBLIC_API(void)
+JS_smprintf_free(char *mem)
 {
-        js_free(mem);
+    js_free(mem);
 }
 
-JS_PUBLIC_API(char *) JS_vsmprintf(const char *fmt, va_list ap)
+JS_PUBLIC_API(char *)
+JS_vsmprintf(const char *fmt, va_list ap)
 {
     SprintfState ss;
     int rv;
 
     ss.stuff = GrowStuff;
     ss.base = 0;
     ss.cur = 0;
     ss.maxlen = 0;
@@ -1107,96 +1033,98 @@ JS_PUBLIC_API(char *) JS_vsmprintf(const
     if (rv < 0) {
         js_free(ss.base);
         return 0;
     }
     return ss.base;
 }
 
 /*
-** Stuff routine that discards overflow data
-*/
-static int LimitStuff(SprintfState *ss, const char *sp, uint32_t len)
+ * Stuff routine that discards overflow data
+ */
+static int
+LimitStuff(SprintfState *ss, const char *sp, size_t len)
 {
-    uint32_t limit = ss->maxlen - (ss->cur - ss->base);
+    size_t limit = ss->maxlen - (ss->cur - ss->base);
 
-    if (len > limit) {
+    if (len > limit)
         len = limit;
-    }
     while (len) {
         --len;
         *ss->cur++ = *sp++;
     }
     return 0;
 }
 
 /*
-** sprintf into a fixed size buffer. Make sure there is a NUL at the end
-** when finished.
-*/
-JS_PUBLIC_API(uint32_t) JS_snprintf(char *out, uint32_t outlen, const char *fmt, ...)
+ * sprintf into a fixed size buffer. Make sure there is a NUL at the end
+ * when finished.
+ */
+JS_PUBLIC_API(uint32_t)
+JS_snprintf(char *out, uint32_t outlen, const char *fmt, ...)
 {
     va_list ap;
     int rv;
 
     JS_ASSERT(int32_t(outlen) > 0);
-    if (int32_t(outlen) <= 0) {
+    if (int32_t(outlen) <= 0)
         return 0;
-    }
 
     va_start(ap, fmt);
     rv = JS_vsnprintf(out, outlen, fmt, ap);
     va_end(ap);
     return rv;
 }
 
-JS_PUBLIC_API(uint32_t) JS_vsnprintf(char *out, uint32_t outlen,const char *fmt,
-                                     va_list ap)
+JS_PUBLIC_API(uint32_t)
+JS_vsnprintf(char *out, uint32_t outlen, const char *fmt, va_list ap)
 {
     SprintfState ss;
     uint32_t n;
 
     JS_ASSERT(int32_t(outlen) > 0);
     if (int32_t(outlen) <= 0) {
         return 0;
     }
 
     ss.stuff = LimitStuff;
     ss.base = out;
     ss.cur = out;
     ss.maxlen = outlen;
     (void) dosprintf(&ss, fmt, ap);
 
     /* If we added chars, and we didn't append a null, do it now. */
-    if( (ss.cur != ss.base) && (ss.cur[-1] != '\0') )
+    if (ss.cur != ss.base && ss.cur[-1] != '\0')
         ss.cur[-1] = '\0';
 
     n = ss.cur - ss.base;
     return n ? n - 1 : n;
 }
 
-JS_PUBLIC_API(char *) JS_sprintf_append(char *last, const char *fmt, ...)
+JS_PUBLIC_API(char *)
+JS_sprintf_append(char *last, const char *fmt, ...)
 {
     va_list ap;
     char *rv;
 
     va_start(ap, fmt);
     rv = JS_vsprintf_append(last, fmt, ap);
     va_end(ap);
     return rv;
 }
 
-JS_PUBLIC_API(char *) JS_vsprintf_append(char *last, const char *fmt, va_list ap)
+JS_PUBLIC_API(char *)
+JS_vsprintf_append(char *last, const char *fmt, va_list ap)
 {
     SprintfState ss;
     int rv;
 
     ss.stuff = GrowStuff;
     if (last) {
-        int lastlen = strlen(last);
+        size_t lastlen = strlen(last);
         ss.base = last;
         ss.cur = last + lastlen;
         ss.maxlen = lastlen;
     } else {
         ss.base = 0;
         ss.cur = 0;
         ss.maxlen = 0;
     }
--- a/js/src/jsprf.h
+++ b/js/src/jsprf.h
@@ -53,27 +53,15 @@ extern JS_PUBLIC_API(void) JS_smprintf_f
 ** the malloc'd buffer. sprintf will append data to the end of last,
 ** growing it as necessary using realloc. If last is nullptr, JS_sprintf_append
 ** will allocate the initial string. The return value is the new value of
 ** last for subsequent calls, or nullptr if there is a malloc failure.
 */
 extern JS_PUBLIC_API(char*) JS_sprintf_append(char *last, const char *fmt, ...);
 
 /*
-** sprintf into a function. The function "f" is called with a string to
-** place into the output. "arg" is an opaque pointer used by the stuff
-** function to hold any state needed to do the storage of the output
-** data. The return value is a count of the number of characters fed to
-** the stuff function, or (uint32_t)-1 if an error occurs.
-*/
-typedef int (*JSStuffFunc)(void *arg, const char *s, uint32_t slen);
-
-extern JS_PUBLIC_API(uint32_t) JS_sxprintf(JSStuffFunc f, void *arg, const char *fmt, ...);
-
-/*
 ** va_list forms of the above.
 */
 extern JS_PUBLIC_API(uint32_t) JS_vsnprintf(char *out, uint32_t outlen, const char *fmt, va_list ap);
 extern JS_PUBLIC_API(char*) JS_vsmprintf(const char *fmt, va_list ap);
 extern JS_PUBLIC_API(char*) JS_vsprintf_append(char *last, const char *fmt, va_list ap);
-extern JS_PUBLIC_API(uint32_t) JS_vsxprintf(JSStuffFunc f, void *arg, const char *fmt, va_list ap);
 
 #endif /* jsprf_h */