Bug 730805 - Provide mozilla/IntegerPrintfMacros.h to implement the PRI* macros portion of the <inttypes.h> interface. r=espindola
authorJeff Walden <jwalden@mit.edu>
Thu, 15 Dec 2011 00:27:42 -0500
changeset 145320 a90c62555235c1525c3134ec030736be5c51de6a
parent 145319 7d8b339221780205a0f16a83b159e23eabf81670
child 145321 75556cd1a5234a95e0a542dc5122983642678881
push id2483
push userryanvm@gmail.com
push dateTue, 03 Sep 2013 21:45:49 +0000
treeherderfx-team@e3785e299ab6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersespindola
bugs730805
milestone26.0a1
Bug 730805 - Provide mozilla/IntegerPrintfMacros.h to implement the PRI* macros portion of the <inttypes.h> interface. r=espindola
configure.in
ipc/chromium/src/base/basictypes.h
js/public/RequiredDefines.h
js/src/configure.in
mfbt/IntegerPrintfMacros.h
mfbt/MSIntTypes.h
mfbt/exported_headers.mk
mfbt/tests/TestIntegerPrintfMacros.cpp
mfbt/tests/TestPoisonArea.cpp
mfbt/tests/moz.build
mozilla-config.h.in
security/manager/boot/src/Makefile.in
--- a/configure.in
+++ b/configure.in
@@ -1728,16 +1728,26 @@ case "$host" in
     ;;
 
 *)
     HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX"
     HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}"
     ;;
 esac
 
+dnl Check for using a custom <inttypes.h> implementation
+dnl ========================================================
+AC_MSG_CHECKING(for custom <inttypes.h> implementation)
+if test "$MOZ_CUSTOM_INTTYPES_H"; then
+  AC_DEFINE_UNQUOTED(MOZ_CUSTOM_INTTYPES_H, "$MOZ_CUSTOM_INTTYPES_H")
+  AC_MSG_RESULT(using $MOZ_CUSTOM_INTTYPES_H)
+else
+  AC_MSG_RESULT(none specified)
+fi
+
 dnl Get mozilla version from central milestone file
 MOZILLA_VERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir`
 MOZILLA_UAVERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir -uaversion`
 
 dnl Get version of various core apps from the version files.
 FIREFOX_VERSION=`cat $_topsrcdir/browser/config/version.txt`
 
 if test -z "$FIREFOX_VERSION"; then
--- a/ipc/chromium/src/base/basictypes.h
+++ b/ipc/chromium/src/base/basictypes.h
@@ -7,17 +7,17 @@
 
 #include <limits.h>         // So we can set the bounds of our types
 #include <stddef.h>         // For size_t
 #include <string.h>         // for memcpy
 
 #include "base/port.h"    // Types that only need exist on certain systems
 
 #include "mozilla/Assertions.h"
-#include <stdint.h>
+#include "mozilla/IntegerPrintfMacros.h"
 
 // A type to represent a Unicode code-point value. As of Unicode 4.0,
 // such values require up to 21 bits.
 // (For type-checking on pointers, make this explicitly signed,
 // and it should always be the signed version of whatever int32_t is.)
 typedef signed int         char32;
 
 const uint8_t  kuint8max  = (( uint8_t) 0xFF);
@@ -30,25 +30,20 @@ const  int16_t kint16min  = (( int16_t) 
 const  int16_t kint16max  = (( int16_t) 0x7FFF);
 const  int32_t kint32min  = (( int32_t) 0x80000000);
 const  int32_t kint32max  = (( int32_t) 0x7FFFFFFF);
 const  int64_t kint64min  = (( int64_t) GG_LONGLONG(0x8000000000000000));
 const  int64_t kint64max  = (( int64_t) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
 
 // Platform- and hardware-dependent printf specifiers
 #  if defined(OS_POSIX)
-#    define __STDC_FORMAT_MACROS 1
-#    include <inttypes.h>           // for 64-bit integer format macros
 #    define PRId64L "I64d"
 #    define PRIu64L "I64u"
 #    define PRIx64L "I64x"
 #  elif defined(OS_WIN)
-#    define PRId64 "I64d"
-#    define PRIu64 "I64u"
-#    define PRIx64 "I64x"
 #    define PRId64L L"I64d"
 #    define PRIu64L L"I64u"
 #    define PRIx64L L"I64x"
 #  endif
 
 // A macro to disallow the copy constructor and operator= functions
 // This should be used in the private: declarations for a class
 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
--- a/js/public/RequiredDefines.h
+++ b/js/public/RequiredDefines.h
@@ -10,14 +10,22 @@
  * or SpiderMonkey public headers may not work correctly.
  */
 
 #ifndef js_RequiredDefines_h
 #define js_RequiredDefines_h
 
 /*
  * The c99 defining the limit macros (UINT32_MAX for example), says:
- * C++ implementations should define these macros only when __STDC_LIMIT_MACROS
- * is defined before <stdint.h> is included.
+ *
+ *   C++ implementations should define these macros only when
+ *   __STDC_LIMIT_MACROS is defined before <stdint.h> is included.
+ *
+ * The same also occurs with __STDC_CONSTANT_MACROS for the constant macros
+ * (INT8_C for example) used to specify a literal constant of the proper type,
+ * and with __STDC_FORMAT_MACROS for the format macros (PRId32 for example) used
+ * with the fprintf function family.
  */
 #define __STDC_LIMIT_MACROS
+#define __STDC_CONSTANT_MACROS
+#define __STDC_FORMAT_MACROS
 
 #endif /* js_RequiredDefines_h */
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1354,16 +1354,26 @@ case "$host" in
     ;;
 
 *)
     HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX"
     HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}"
     ;;
 esac
 
+dnl Check for using a custom <inttypes.h> implementation
+dnl ========================================================
+AC_MSG_CHECKING(for custom <inttypes.h> implementation)
+if test "$MOZ_CUSTOM_INTTYPES_H"; then
+  AC_DEFINE_UNQUOTED(MOZ_CUSTOM_INTTYPES_H, "$MOZ_CUSTOM_INTTYPES_H")
+  AC_MSG_RESULT(using $MOZ_CUSTOM_INTTYPES_H)
+else
+  AC_MSG_RESULT(none specified)
+fi
+
 MOZ_DOING_LTO(lto_is_enabled)
 
 dnl ========================================================
 dnl System overrides of the defaults for target
 dnl ========================================================
 
 case "$target" in
 *-aix*)
new file mode 100644
--- /dev/null
+++ b/mfbt/IntegerPrintfMacros.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/* Implements the C99 <inttypes.h> interface, minus the SCN* format macros. */
+
+#ifndef mozilla_IntegerPrintfMacros_h_
+#define mozilla_IntegerPrintfMacros_h_
+
+/*
+ * MSVC++ doesn't include <inttypes.h>, even in versions shipping <stdint.h>, so
+ * we have to reimplement it there.  Note: <inttypes.h> #includes <stdint.h>.
+ *
+ * Note that this header DOES NOT implement <inttypes.h>'s scanf macros.  MSVC's
+ * scanf doesn't have sufficient format specifier support to implement them
+ * (specifically, to implement scanning into an 8-bit location).
+ *
+ * http://stackoverflow.com/questions/3036396/scanfd-char-char-as-int-format-string
+ *
+ * Moreover, scanf is a footgun: if the input number exceeds the bounds of the
+ * target type, behavior is undefined (in the compiler sense: that is, this code
+ * could overwrite your hard drive with zeroes):
+ *
+ *   uint8_t u;
+ *   sscanf("256", "%" SCNu8, &u); // BAD
+ *
+ * This header will sometimes provide SCN* macros, by dint of being implemented
+ * using <inttypes.h>.  But for these reasons, *never* use them!
+ */
+
+#if defined(MOZ_CUSTOM_INTTYPES_H)
+#  include MOZ_CUSTOM_INTTYPES_H
+#elif defined(_MSC_VER)
+#  include "mozilla/MSIntTypes.h"
+#else
+#  include <inttypes.h>
+#endif
+
+#endif  /* mozilla_IntegerPrintfMacros_h_ */
--- a/mfbt/MSIntTypes.h
+++ b/mfbt/MSIntTypes.h
@@ -35,17 +35,17 @@
 
 #ifndef _MSC_INTTYPES_H_ // [
 #define _MSC_INTTYPES_H_
 
 #if _MSC_VER > 1000
 #pragma once
 #endif
 
-#include "stdint.h"
+#include <stdint.h>
 
 // 7.8 Format conversion of integer types
 
 typedef struct {
    intmax_t quot;
    intmax_t rem;
 } imaxdiv_t;
 
@@ -146,125 +146,18 @@ typedef struct {
 #define PRIxMAX     "I64x"
 #define PRIXMAX     "I64X"
 
 #define PRIoPTR     "Io"
 #define PRIuPTR     "Iu"
 #define PRIxPTR     "Ix"
 #define PRIXPTR     "IX"
 
-// The fscanf macros for signed integers are:
-#define SCNd8       "d"
-#define SCNi8       "i"
-#define SCNdLEAST8  "d"
-#define SCNiLEAST8  "i"
-#define SCNdFAST8   "d"
-#define SCNiFAST8   "i"
-
-#define SCNd16       "hd"
-#define SCNi16       "hi"
-#define SCNdLEAST16  "hd"
-#define SCNiLEAST16  "hi"
-#define SCNdFAST16   "hd"
-#define SCNiFAST16   "hi"
-
-#define SCNd32       "ld"
-#define SCNi32       "li"
-#define SCNdLEAST32  "ld"
-#define SCNiLEAST32  "li"
-#define SCNdFAST32   "ld"
-#define SCNiFAST32   "li"
-
-#define SCNd64       "I64d"
-#define SCNi64       "I64i"
-#define SCNdLEAST64  "I64d"
-#define SCNiLEAST64  "I64i"
-#define SCNdFAST64   "I64d"
-#define SCNiFAST64   "I64i"
-
-#define SCNdMAX     "I64d"
-#define SCNiMAX     "I64i"
-
-#ifdef _WIN64 // [
-#  define SCNdPTR     "I64d"
-#  define SCNiPTR     "I64i"
-#else  // _WIN64 ][
-#  define SCNdPTR     "ld"
-#  define SCNiPTR     "li"
-#endif  // _WIN64 ]
-
-// The fscanf macros for unsigned integers are:
-#define SCNo8       "o"
-#define SCNu8       "u"
-#define SCNx8       "x"
-#define SCNX8       "X"
-#define SCNoLEAST8  "o"
-#define SCNuLEAST8  "u"
-#define SCNxLEAST8  "x"
-#define SCNXLEAST8  "X"
-#define SCNoFAST8   "o"
-#define SCNuFAST8   "u"
-#define SCNxFAST8   "x"
-#define SCNXFAST8   "X"
-
-#define SCNo16       "ho"
-#define SCNu16       "hu"
-#define SCNx16       "hx"
-#define SCNX16       "hX"
-#define SCNoLEAST16  "ho"
-#define SCNuLEAST16  "hu"
-#define SCNxLEAST16  "hx"
-#define SCNXLEAST16  "hX"
-#define SCNoFAST16   "ho"
-#define SCNuFAST16   "hu"
-#define SCNxFAST16   "hx"
-#define SCNXFAST16   "hX"
-
-#define SCNo32       "lo"
-#define SCNu32       "lu"
-#define SCNx32       "lx"
-#define SCNX32       "lX"
-#define SCNoLEAST32  "lo"
-#define SCNuLEAST32  "lu"
-#define SCNxLEAST32  "lx"
-#define SCNXLEAST32  "lX"
-#define SCNoFAST32   "lo"
-#define SCNuFAST32   "lu"
-#define SCNxFAST32   "lx"
-#define SCNXFAST32   "lX"
-
-#define SCNo64       "I64o"
-#define SCNu64       "I64u"
-#define SCNx64       "I64x"
-#define SCNX64       "I64X"
-#define SCNoLEAST64  "I64o"
-#define SCNuLEAST64  "I64u"
-#define SCNxLEAST64  "I64x"
-#define SCNXLEAST64  "I64X"
-#define SCNoFAST64   "I64o"
-#define SCNuFAST64   "I64u"
-#define SCNxFAST64   "I64x"
-#define SCNXFAST64   "I64X"
-
-#define SCNoMAX     "I64o"
-#define SCNuMAX     "I64u"
-#define SCNxMAX     "I64x"
-#define SCNXMAX     "I64X"
-
-#ifdef _WIN64 // [
-#  define SCNoPTR     "I64o"
-#  define SCNuPTR     "I64u"
-#  define SCNxPTR     "I64x"
-#  define SCNXPTR     "I64X"
-#else  // _WIN64 ][
-#  define SCNoPTR     "lo"
-#  define SCNuPTR     "lu"
-#  define SCNxPTR     "lx"
-#  define SCNXPTR     "lX"
-#endif  // _WIN64 ]
+// DO NOT SUPPORT THE scanf MACROS!  See the comment at the top of
+// IntegerPrintfMacros.h.
 
 #endif // __STDC_FORMAT_MACROS ]
 
 // 7.8.2 Functions for greatest-width integer types
 
 // 7.8.2.1 The imaxabs function
 #define imaxabs _abs64
 
--- a/mfbt/exported_headers.mk
+++ b/mfbt/exported_headers.mk
@@ -23,16 +23,17 @@ EXPORTS_mozilla += \
   Constants.h \
   DebugOnly.h \
   decimal/Decimal.h \
   Endian.h \
   EnumSet.h \
   FloatingPoint.h \
   GuardObjects.h \
   HashFunctions.h \
+  IntegerPrintfMacros.h \
   Likely.h \
   LinkedList.h \
   MathAlgorithms.h \
   Maybe.h \
   MemoryChecking.h \
   MemoryReporting.h \
   MSIntTypes.h \
   Move.h \
new file mode 100644
--- /dev/null
+++ b/mfbt/tests/TestIntegerPrintfMacros.cpp
@@ -0,0 +1,1264 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/IntegerPrintfMacros.h" // this must pick up <stdint.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Output array and poisoning method shared by all tests. */
+static char output[32];
+
+static void
+PoisonOutput()
+{
+  memset(output, 0xDA, sizeof(output));
+}
+
+/*
+ * The fprintf macros for signed integers are:
+ *
+ *   PRIdN   PRIdLEASTN   PRIdFASTN   PRIdMAX   PRIdPTR
+ *   PRIiN   PRIiLEASTN   PRIiFASTN   PRIiMAX   PRIiPTR
+ *
+ * In these names N is the width of the type as described in C99 7.18.1.
+ */
+
+static void
+TestPrintSigned8()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRId8, int8_t(-17));
+  MOZ_ASSERT(!strcmp(output, "-17"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIi8, int8_t(42));
+  MOZ_ASSERT(!strcmp(output, "42"));
+}
+
+static void
+TestPrintSigned16()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRId16, int16_t(-289));
+  MOZ_ASSERT(!strcmp(output, "-289"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIi16, int16_t(728));
+  MOZ_ASSERT(!strcmp(output, "728"));
+}
+
+static void
+TestPrintSigned32()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRId32, int32_t(-342178));
+  MOZ_ASSERT(!strcmp(output, "-342178"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIi32, int32_t(5719283));
+  MOZ_ASSERT(!strcmp(output, "5719283"));
+}
+
+static void
+TestPrintSigned64()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRId64, int64_t(-INT64_C(432157943248732)));
+  MOZ_ASSERT(!strcmp(output, "-432157943248732"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIi64, int64_t(INT64_C(325719232983)));
+  MOZ_ASSERT(!strcmp(output, "325719232983"));
+}
+
+static void
+TestPrintSignedN()
+{
+  TestPrintSigned8();
+  TestPrintSigned16();
+  TestPrintSigned32();
+  TestPrintSigned64();
+}
+
+static void
+TestPrintSignedLeast8()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdLEAST8, int_least8_t(-17));
+  MOZ_ASSERT(!strcmp(output, "-17"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiLEAST8, int_least8_t(42));
+  MOZ_ASSERT(!strcmp(output, "42"));
+}
+
+static void
+TestPrintSignedLeast16()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdLEAST16, int_least16_t(-289));
+  MOZ_ASSERT(!strcmp(output, "-289"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiLEAST16, int_least16_t(728));
+  MOZ_ASSERT(!strcmp(output, "728"));
+}
+
+static void
+TestPrintSignedLeast32()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdLEAST32, int_least32_t(-342178));
+  MOZ_ASSERT(!strcmp(output, "-342178"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiLEAST32, int_least32_t(5719283));
+  MOZ_ASSERT(!strcmp(output, "5719283"));
+}
+
+static void
+TestPrintSignedLeast64()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdLEAST64, int_least64_t(-INT64_C(432157943248732)));
+  MOZ_ASSERT(!strcmp(output, "-432157943248732"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiLEAST64, int_least64_t(INT64_C(325719232983)));
+  MOZ_ASSERT(!strcmp(output, "325719232983"));
+}
+
+static void
+TestPrintSignedLeastN()
+{
+  TestPrintSignedLeast8();
+  TestPrintSignedLeast16();
+  TestPrintSignedLeast32();
+  TestPrintSignedLeast64();
+}
+
+static void
+TestPrintSignedFast8()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdFAST8, int_fast8_t(-17));
+  MOZ_ASSERT(!strcmp(output, "-17"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiFAST8, int_fast8_t(42));
+  MOZ_ASSERT(!strcmp(output, "42"));
+}
+
+static void
+TestPrintSignedFast16()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdFAST16, int_fast16_t(-289));
+  MOZ_ASSERT(!strcmp(output, "-289"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiFAST16, int_fast16_t(728));
+  MOZ_ASSERT(!strcmp(output, "728"));
+}
+
+static void
+TestPrintSignedFast32()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdFAST32, int_fast32_t(-342178));
+  MOZ_ASSERT(!strcmp(output, "-342178"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiFAST32, int_fast32_t(5719283));
+  MOZ_ASSERT(!strcmp(output, "5719283"));
+}
+
+static void
+TestPrintSignedFast64()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdFAST64, int_fast64_t(-INT64_C(432157943248732)));
+  MOZ_ASSERT(!strcmp(output, "-432157943248732"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiFAST64, int_fast64_t(INT64_C(325719232983)));
+  MOZ_ASSERT(!strcmp(output, "325719232983"));
+}
+
+static void
+TestPrintSignedFastN()
+{
+  TestPrintSignedFast8();
+  TestPrintSignedFast16();
+  TestPrintSignedFast32();
+  TestPrintSignedFast64();
+}
+
+static void
+TestPrintSignedMax()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdMAX, intmax_t(-INTMAX_C(432157943248732)));
+  MOZ_ASSERT(!strcmp(output, "-432157943248732"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiMAX, intmax_t(INTMAX_C(325719232983)));
+  MOZ_ASSERT(!strcmp(output, "325719232983"));
+}
+
+static void
+TestPrintSignedPtr()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIdPTR, intptr_t(reinterpret_cast<void*>(12345678)));
+  MOZ_ASSERT(!strcmp(output, "12345678"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIiPTR, intptr_t(reinterpret_cast<void*>(87654321)));
+  MOZ_ASSERT(!strcmp(output, "87654321"));
+}
+
+static void
+TestPrintSigned()
+{
+  TestPrintSignedN();
+  TestPrintSignedLeastN();
+  TestPrintSignedFastN();
+  TestPrintSignedMax();
+  TestPrintSignedPtr();
+}
+
+/*
+ * The fprintf macros for unsigned integers are:
+ *
+ *   PRIoN   PRIoLEASTN   PRIoFASTN   PRIoMAX   PRIoPTR
+ *   PRIuN   PRIuLEASTN   PRIuFASTN   PRIuMAX   PRIuPTR
+ *   PRIxN   PRIxLEASTN   PRIxFASTN   PRIxMAX   PRIxPTR
+ *   PRIXN   PRIXLEASTN   PRIXFASTN   PRIXMAX   PRIXPTR
+ *
+ * In these names N is the width of the type as described in C99 7.18.1.
+ */
+
+static void
+TestPrintUnsigned8()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIo8, uint8_t(042));
+  MOZ_ASSERT(!strcmp(output, "42"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIu8, uint8_t(17));
+  MOZ_ASSERT(!strcmp(output, "17"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIx8, uint8_t(0x2a));
+  MOZ_ASSERT(!strcmp(output, "2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIX8, uint8_t(0xCD));
+  MOZ_ASSERT(!strcmp(output, "CD"));
+}
+
+static void
+TestPrintUnsigned16()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIo16, uint16_t(04242));
+  MOZ_ASSERT(!strcmp(output, "4242"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIu16, uint16_t(1717));
+  MOZ_ASSERT(!strcmp(output, "1717"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIx16, uint16_t(0x2a2a));
+  MOZ_ASSERT(!strcmp(output, "2a2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIX16, uint16_t(0xCDCD));
+  MOZ_ASSERT(!strcmp(output, "CDCD"));
+}
+
+static void
+TestPrintUnsigned32()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIo32, uint32_t(0424242));
+  MOZ_ASSERT(!strcmp(output, "424242"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIu32, uint32_t(171717));
+  MOZ_ASSERT(!strcmp(output, "171717"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIx32, uint32_t(0x2a2a2a));
+  MOZ_ASSERT(!strcmp(output, "2a2a2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIX32, uint32_t(0xCDCDCD));
+  MOZ_ASSERT(!strcmp(output, "CDCDCD"));
+}
+
+static void
+TestPrintUnsigned64()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIo64, uint64_t(UINT64_C(0424242424242)));
+  MOZ_ASSERT(!strcmp(output, "424242424242"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIu64, uint64_t(UINT64_C(17171717171717171717)));
+  MOZ_ASSERT(!strcmp(output, "17171717171717171717"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIx64, uint64_t(UINT64_C(0x2a2a2a2a2a2a2a)));
+  MOZ_ASSERT(!strcmp(output, "2a2a2a2a2a2a2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIX64, uint64_t(UINT64_C(0xCDCDCDCDCDCD)));
+  MOZ_ASSERT(!strcmp(output, "CDCDCDCDCDCD"));
+}
+
+static void
+TestPrintUnsignedN()
+{
+  TestPrintUnsigned8();
+  TestPrintUnsigned16();
+  TestPrintUnsigned32();
+  TestPrintUnsigned64();
+}
+
+static void
+TestPrintUnsignedLeast8()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoLEAST8, uint_least8_t(042));
+  MOZ_ASSERT(!strcmp(output, "42"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuLEAST8, uint_least8_t(17));
+  MOZ_ASSERT(!strcmp(output, "17"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxLEAST8, uint_least8_t(0x2a));
+  MOZ_ASSERT(!strcmp(output, "2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXLEAST8, uint_least8_t(0xCD));
+  MOZ_ASSERT(!strcmp(output, "CD"));
+}
+
+static void
+TestPrintUnsignedLeast16()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoLEAST16, uint_least16_t(04242));
+  MOZ_ASSERT(!strcmp(output, "4242"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuLEAST16, uint_least16_t(1717));
+  MOZ_ASSERT(!strcmp(output, "1717"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxLEAST16, uint_least16_t(0x2a2a));
+  MOZ_ASSERT(!strcmp(output, "2a2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXLEAST16, uint_least16_t(0xCDCD));
+  MOZ_ASSERT(!strcmp(output, "CDCD"));
+}
+
+static void
+TestPrintUnsignedLeast32()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoLEAST32, uint_least32_t(0424242));
+  MOZ_ASSERT(!strcmp(output, "424242"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuLEAST32, uint_least32_t(171717));
+  MOZ_ASSERT(!strcmp(output, "171717"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxLEAST32, uint_least32_t(0x2a2a2a));
+  MOZ_ASSERT(!strcmp(output, "2a2a2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXLEAST32, uint_least32_t(0xCDCDCD));
+  MOZ_ASSERT(!strcmp(output, "CDCDCD"));
+}
+
+static void
+TestPrintUnsignedLeast64()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoLEAST64, uint_least64_t(UINT64_C(0424242424242)));
+  MOZ_ASSERT(!strcmp(output, "424242424242"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuLEAST64, uint_least64_t(UINT64_C(17171717171717171717)));
+  MOZ_ASSERT(!strcmp(output, "17171717171717171717"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxLEAST64, uint_least64_t(UINT64_C(0x2a2a2a2a2a2a2a)));
+  MOZ_ASSERT(!strcmp(output, "2a2a2a2a2a2a2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXLEAST64, uint_least64_t(UINT64_C(0xCDCDCDCDCDCD)));
+  MOZ_ASSERT(!strcmp(output, "CDCDCDCDCDCD"));
+}
+
+static void
+TestPrintUnsignedLeastN()
+{
+  TestPrintUnsignedLeast8();
+  TestPrintUnsignedLeast16();
+  TestPrintUnsignedLeast32();
+  TestPrintUnsignedLeast64();
+}
+
+static void
+TestPrintUnsignedFast8()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoFAST8, uint_fast8_t(042));
+  MOZ_ASSERT(!strcmp(output, "42"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuFAST8, uint_fast8_t(17));
+  MOZ_ASSERT(!strcmp(output, "17"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxFAST8, uint_fast8_t(0x2a));
+  MOZ_ASSERT(!strcmp(output, "2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXFAST8, uint_fast8_t(0xCD));
+  MOZ_ASSERT(!strcmp(output, "CD"));
+}
+
+static void
+TestPrintUnsignedFast16()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoFAST16, uint_fast16_t(04242));
+  MOZ_ASSERT(!strcmp(output, "4242"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuFAST16, uint_fast16_t(1717));
+  MOZ_ASSERT(!strcmp(output, "1717"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxFAST16, uint_fast16_t(0x2a2a));
+  MOZ_ASSERT(!strcmp(output, "2a2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXFAST16, uint_fast16_t(0xCDCD));
+  MOZ_ASSERT(!strcmp(output, "CDCD"));
+}
+
+static void
+TestPrintUnsignedFast32()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoFAST32, uint_fast32_t(0424242));
+  MOZ_ASSERT(!strcmp(output, "424242"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuFAST32, uint_fast32_t(171717));
+  MOZ_ASSERT(!strcmp(output, "171717"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxFAST32, uint_fast32_t(0x2a2a2a));
+  MOZ_ASSERT(!strcmp(output, "2a2a2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXFAST32, uint_fast32_t(0xCDCDCD));
+  MOZ_ASSERT(!strcmp(output, "CDCDCD"));
+}
+
+static void
+TestPrintUnsignedFast64()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoFAST64, uint_fast64_t(UINT64_C(0424242424242)));
+  MOZ_ASSERT(!strcmp(output, "424242424242"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuFAST64, uint_fast64_t(UINT64_C(17171717171717171717)));
+  MOZ_ASSERT(!strcmp(output, "17171717171717171717"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxFAST64, uint_fast64_t(UINT64_C(0x2a2a2a2a2a2a2a)));
+  MOZ_ASSERT(!strcmp(output, "2a2a2a2a2a2a2a"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXFAST64, uint_fast64_t(UINT64_C(0xCDCDCDCDCDCD)));
+  MOZ_ASSERT(!strcmp(output, "CDCDCDCDCDCD"));
+}
+
+static void
+TestPrintUnsignedFastN()
+{
+  TestPrintUnsignedFast8();
+  TestPrintUnsignedFast16();
+  TestPrintUnsignedFast32();
+  TestPrintUnsignedFast64();
+}
+
+static void
+TestPrintUnsignedMax()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoMAX, uintmax_t(UINTMAX_C(432157943248732)));
+  MOZ_ASSERT(!strcmp(output, "14220563454333534"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuMAX, uintmax_t(UINTMAX_C(325719232983)));
+  MOZ_ASSERT(!strcmp(output, "325719232983"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxMAX, uintmax_t(UINTMAX_C(327281321873)));
+  MOZ_ASSERT(!strcmp(output, "4c337ca791"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXMAX, uintmax_t(UINTMAX_C(912389523743523)));
+  MOZ_ASSERT(!strcmp(output, "33DD03D75A323"));
+}
+
+static void
+TestPrintUnsignedPtr()
+{
+  PoisonOutput();
+  sprintf(output, "%" PRIoPTR, uintptr_t(reinterpret_cast<void*>(12345678)));
+  MOZ_ASSERT(!strcmp(output, "57060516"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIuPTR, uintptr_t(reinterpret_cast<void*>(87654321)));
+  MOZ_ASSERT(!strcmp(output, "87654321"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIxPTR, uintptr_t(reinterpret_cast<void*>(0x4c3a791)));
+  MOZ_ASSERT(!strcmp(output, "4c3a791"));
+
+  PoisonOutput();
+  sprintf(output, "%" PRIXPTR, uintptr_t(reinterpret_cast<void*>(0xF328DB)));
+  MOZ_ASSERT(!strcmp(output, "F328DB"));
+}
+
+static void
+TestPrintUnsigned()
+{
+  TestPrintUnsignedN();
+  TestPrintUnsignedLeastN();
+  TestPrintUnsignedFastN();
+  TestPrintUnsignedMax();
+  TestPrintUnsignedPtr();
+}
+
+static void
+TestPrint()
+{
+  TestPrintSigned();
+  TestPrintUnsigned();
+}
+
+/*
+ * The fscanf macros for signed integers are:
+ *
+ *   SCNdN   SCNdLEASTN   SCNdFASTN   SCNdMAX   SCNdPTR
+ *   SCNiN   SCNiLEASTN   SCNiFASTN   SCNiMAX   SCNiPTR
+ *
+ * In these names N is the width of the type as described in C99 7.18.1.
+ */
+
+/*
+ * MSVC's scanf is insufficiently powerful to implement all the SCN* macros.
+ * Rather than support some subset of them, we instead support none of them.
+ * See the comment at the top of IntegerPrintfMacros.h.  But in case we ever do
+ * support them, the following tests should adequately test implementation
+ * correctness.  (Indeed, these tests *revealed* MSVC's limitations.)
+ *
+ * That said, even if MSVC ever picks up complete support, we still probably
+ * don't want to support these, because of the undefined-behavior issue noted
+ * further down in the comment atop IntegerPrintfMacros.h.
+ */
+#define SHOULD_TEST_SCANF_MACROS 0
+
+#if SHOULD_TEST_SCANF_MACROS
+
+/*
+ * glibc header definitions for SCN{d,i,o,u,x}{,LEAST,FAST}8 use the "hh" length
+ * modifier, which is new in C99 (and C++11, by reference).  We compile this
+ * file as C++11, so if "hh" is used in these macros, it's standard.  But some
+ * versions of gcc wrongly think it isn't and warn about a "non-standard"
+ * modifier.  And since these tests mostly exist to verify format-macro/type
+ * consistency (particularly through compiler warnings about incorrect formats),
+ * these warnings are unacceptable.  So for now, compile tests for those macros
+ * only if we aren't compiling with gcc.
+ */
+#define SHOULD_TEST_8BIT_FORMAT_MACROS (!(MOZ_IS_GCC))
+
+template<typename T>
+union Input
+{
+    T i;
+    unsigned char pun[16];
+};
+
+template<typename T>
+static void
+PoisonInput(Input<T>& input)
+{
+    memset(input.pun, 0xDA, sizeof(input.pun));
+}
+
+template<typename T>
+static bool
+ExtraBitsUntouched(const Input<T>& input)
+{
+  for (size_t i = sizeof(input.i); i < sizeof(input); i++) {
+    if (input.pun[i] != 0xDA)
+      return false;
+  }
+
+  return true;
+}
+
+static void
+TestScanSigned8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<int8_t> u;
+
+  PoisonInput(u);
+  sscanf("-17", "%" SCNd8, &u.i);
+  MOZ_ASSERT(u.i == -17);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042", "%" SCNi8, &u.i);
+  MOZ_ASSERT(u.i == 042);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanSigned16()
+{
+  Input<int16_t> u;
+
+  PoisonInput(u);
+  sscanf("-1742", "%" SCNd16, &u.i);
+  MOZ_ASSERT(u.i == -1742);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04217", "%" SCNi16, &u.i);
+  MOZ_ASSERT(u.i == 04217);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSigned32()
+{
+  Input<int32_t> u;
+
+  PoisonInput(u);
+  sscanf("-174257", "%" SCNd32, &u.i);
+  MOZ_ASSERT(u.i == -174257);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("0423571", "%" SCNi32, &u.i);
+  MOZ_ASSERT(u.i == 0423571);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSigned64()
+{
+  Input<int64_t> u;
+
+  PoisonInput(u);
+  sscanf("-17425238927232", "%" SCNd64, &u.i);
+  MOZ_ASSERT(u.i == -INT64_C(17425238927232));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042333576571", "%" SCNi64, &u.i);
+  MOZ_ASSERT(u.i == INT64_C(042333576571));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedN()
+{
+  TestScanSigned8();
+  TestScanSigned16();
+  TestScanSigned32();
+  TestScanSigned64();
+}
+
+static void
+TestScanSignedLeast8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<int_least8_t> u;
+
+  PoisonInput(u);
+  sscanf("-17", "%" SCNdLEAST8, &u.i);
+  MOZ_ASSERT(u.i == -17);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042", "%" SCNiLEAST8, &u.i);
+  MOZ_ASSERT(u.i == 042);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanSignedLeast16()
+{
+  Input<int_least16_t> u;
+
+  PoisonInput(u);
+  sscanf("-1742", "%" SCNdLEAST16, &u.i);
+  MOZ_ASSERT(u.i == -1742);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04217", "%" SCNiLEAST16, &u.i);
+  MOZ_ASSERT(u.i == 04217);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedLeast32()
+{
+  Input<int_least32_t> u;
+
+  PoisonInput(u);
+  sscanf("-174257", "%" SCNdLEAST32, &u.i);
+  MOZ_ASSERT(u.i == -174257);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("0423571", "%" SCNiLEAST32, &u.i);
+  MOZ_ASSERT(u.i == 0423571);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedLeast64()
+{
+  Input<int_least64_t> u;
+
+  PoisonInput(u);
+  sscanf("-17425238927232", "%" SCNdLEAST64, &u.i);
+  MOZ_ASSERT(u.i == -INT64_C(17425238927232));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042333576571", "%" SCNiLEAST64, &u.i);
+  MOZ_ASSERT(u.i == INT64_C(042333576571));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedLeastN()
+{
+  TestScanSignedLeast8();
+  TestScanSignedLeast16();
+  TestScanSignedLeast32();
+  TestScanSignedLeast64();
+}
+
+static void
+TestScanSignedFast8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<int_fast8_t> u;
+
+  PoisonInput(u);
+  sscanf("-17", "%" SCNdFAST8, &u.i);
+  MOZ_ASSERT(u.i == -17);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042", "%" SCNiFAST8, &u.i);
+  MOZ_ASSERT(u.i == 042);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanSignedFast16()
+{
+  Input<int_fast16_t> u;
+
+  PoisonInput(u);
+  sscanf("-1742", "%" SCNdFAST16, &u.i);
+  MOZ_ASSERT(u.i == -1742);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04217", "%" SCNiFAST16, &u.i);
+  MOZ_ASSERT(u.i == 04217);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedFast32()
+{
+  Input<int_fast32_t> u;
+
+  PoisonInput(u);
+  sscanf("-174257", "%" SCNdFAST32, &u.i);
+  MOZ_ASSERT(u.i == -174257);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("0423571", "%" SCNiFAST32, &u.i);
+  MOZ_ASSERT(u.i == 0423571);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedFast64()
+{
+  Input<int_fast64_t> u;
+
+  PoisonInput(u);
+  sscanf("-17425238927232", "%" SCNdFAST64, &u.i);
+  MOZ_ASSERT(u.i == -INT64_C(17425238927232));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042333576571", "%" SCNiFAST64, &u.i);
+  MOZ_ASSERT(u.i == INT64_C(042333576571));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedFastN()
+{
+  TestScanSignedFast8();
+  TestScanSignedFast16();
+  TestScanSignedFast32();
+  TestScanSignedFast64();
+}
+
+static void
+TestScanSignedMax()
+{
+  Input<intmax_t> u;
+
+  PoisonInput(u);
+  sscanf("-432157943248732", "%" SCNdMAX, &u.i);
+  MOZ_ASSERT(u.i == -INTMAX_C(432157943248732));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04233357236571", "%" SCNiMAX, &u.i);
+  MOZ_ASSERT(u.i == INTMAX_C(04233357236571));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedPtr()
+{
+  Input<intptr_t> u;
+
+  PoisonInput(u);
+  sscanf("12345678", "%" SCNdPTR, &u.i);
+  MOZ_ASSERT(u.i == intptr_t(reinterpret_cast<void*>(12345678)));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04233357236", "%" SCNiPTR, &u.i);
+  MOZ_ASSERT(u.i == intptr_t(reinterpret_cast<void*>(04233357236)));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSigned()
+{
+  TestScanSignedN();
+  TestScanSignedLeastN();
+  TestScanSignedFastN();
+  TestScanSignedMax();
+  TestScanSignedPtr();
+}
+
+/*
+ * The fscanf macros for unsigned integers are:
+ *
+ *   SCNoN   SCNoLEASTN   SCNoFASTN   SCNoMAX   SCNoPTR
+ *   SCNuN   SCNuLEASTN   SCNuFASTN   SCNuMAX   SCNuPTR
+ *   SCNxN   SCNxLEASTN   SCNxFASTN   SCNxMAX   SCNxPTR
+ *
+ * In these names N is the width of the type as described in C99 7.18.1.
+ */
+
+static void
+TestScanUnsigned8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<uint8_t> u;
+
+  PoisonInput(u);
+  sscanf("17", "%" SCNo8, &u.i);
+  MOZ_ASSERT(u.i == 017);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("42", "%" SCNu8, &u.i);
+  MOZ_ASSERT(u.i == 42);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2A", "%" SCNx8, &u.i);
+  MOZ_ASSERT(u.i == 0x2A);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanUnsigned16()
+{
+  Input<uint16_t> u;
+
+  PoisonInput(u);
+  sscanf("1742", "%" SCNo16, &u.i);
+  MOZ_ASSERT(u.i == 01742);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217", "%" SCNu16, &u.i);
+  MOZ_ASSERT(u.i == 4217);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABC", "%" SCNx16, &u.i);
+  MOZ_ASSERT(u.i == 0x2ABC);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsigned32()
+{
+  Input<uint32_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742", "%" SCNo32, &u.i);
+  MOZ_ASSERT(u.i == 017421742);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217867", "%" SCNu32, &u.i);
+  MOZ_ASSERT(u.i == 4217867);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABCBEEF", "%" SCNx32, &u.i);
+  MOZ_ASSERT(u.i == 0x2ABCBEEF);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsigned64()
+{
+  Input<uint64_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742173", "%" SCNo64, &u.i);
+  MOZ_ASSERT(u.i == UINT64_C(017421742173));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("421786713579", "%" SCNu64, &u.i);
+  MOZ_ASSERT(u.i == UINT64_C(421786713579));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("DEADBEEF7457E", "%" SCNx64, &u.i);
+  MOZ_ASSERT(u.i == UINT64_C(0xDEADBEEF7457E));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedN()
+{
+  TestScanUnsigned8();
+  TestScanUnsigned16();
+  TestScanUnsigned32();
+  TestScanUnsigned64();
+}
+
+static void
+TestScanUnsignedLeast8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<uint_least8_t> u;
+
+  PoisonInput(u);
+  sscanf("17", "%" SCNoLEAST8, &u.i);
+  MOZ_ASSERT(u.i == 017);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("42", "%" SCNuLEAST8, &u.i);
+  MOZ_ASSERT(u.i == 42);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2A", "%" SCNxLEAST8, &u.i);
+  MOZ_ASSERT(u.i == 0x2A);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanUnsignedLeast16()
+{
+  Input<uint_least16_t> u;
+
+  PoisonInput(u);
+  sscanf("1742", "%" SCNoLEAST16, &u.i);
+  MOZ_ASSERT(u.i == 01742);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217", "%" SCNuLEAST16, &u.i);
+  MOZ_ASSERT(u.i == 4217);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABC", "%" SCNxLEAST16, &u.i);
+  MOZ_ASSERT(u.i == 0x2ABC);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedLeast32()
+{
+  Input<uint_least32_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742", "%" SCNoLEAST32, &u.i);
+  MOZ_ASSERT(u.i == 017421742);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217867", "%" SCNuLEAST32, &u.i);
+  MOZ_ASSERT(u.i == 4217867);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABCBEEF", "%" SCNxLEAST32, &u.i);
+  MOZ_ASSERT(u.i == 0x2ABCBEEF);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedLeast64()
+{
+  Input<uint_least64_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742173", "%" SCNoLEAST64, &u.i);
+  MOZ_ASSERT(u.i == UINT64_C(017421742173));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("421786713579", "%" SCNuLEAST64, &u.i);
+  MOZ_ASSERT(u.i == UINT64_C(421786713579));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("DEADBEEF7457E", "%" SCNxLEAST64, &u.i);
+  MOZ_ASSERT(u.i == UINT64_C(0xDEADBEEF7457E));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedLeastN()
+{
+  TestScanUnsignedLeast8();
+  TestScanUnsignedLeast16();
+  TestScanUnsignedLeast32();
+  TestScanUnsignedLeast64();
+}
+
+static void
+TestScanUnsignedFast8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<uint_fast8_t> u;
+
+  PoisonInput(u);
+  sscanf("17", "%" SCNoFAST8, &u.i);
+  MOZ_ASSERT(u.i == 017);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("42", "%" SCNuFAST8, &u.i);
+  MOZ_ASSERT(u.i == 42);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2A", "%" SCNxFAST8, &u.i);
+  MOZ_ASSERT(u.i == 0x2A);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanUnsignedFast16()
+{
+  Input<uint_fast16_t> u;
+
+  PoisonInput(u);
+  sscanf("1742", "%" SCNoFAST16, &u.i);
+  MOZ_ASSERT(u.i == 01742);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217", "%" SCNuFAST16, &u.i);
+  MOZ_ASSERT(u.i == 4217);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABC", "%" SCNxFAST16, &u.i);
+  MOZ_ASSERT(u.i == 0x2ABC);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedFast32()
+{
+  Input<uint_fast32_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742", "%" SCNoFAST32, &u.i);
+  MOZ_ASSERT(u.i == 017421742);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217867", "%" SCNuFAST32, &u.i);
+  MOZ_ASSERT(u.i == 4217867);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABCBEEF", "%" SCNxFAST32, &u.i);
+  MOZ_ASSERT(u.i == 0x2ABCBEEF);
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedFast64()
+{
+  Input<uint_fast64_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742173", "%" SCNoFAST64, &u.i);
+  MOZ_ASSERT(u.i == UINT64_C(017421742173));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("421786713579", "%" SCNuFAST64, &u.i);
+  MOZ_ASSERT(u.i == UINT64_C(421786713579));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("DEADBEEF7457E", "%" SCNxFAST64, &u.i);
+  MOZ_ASSERT(u.i == UINT64_C(0xDEADBEEF7457E));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedFastN()
+{
+  TestScanUnsignedFast8();
+  TestScanUnsignedFast16();
+  TestScanUnsignedFast32();
+  TestScanUnsignedFast64();
+}
+
+static void
+TestScanUnsignedMax()
+{
+  Input<uintmax_t> u;
+
+  PoisonInput(u);
+  sscanf("14220563454333534", "%" SCNoMAX, &u.i);
+  MOZ_ASSERT(u.i == UINTMAX_C(432157943248732));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("432157943248732", "%" SCNuMAX, &u.i);
+  MOZ_ASSERT(u.i == UINTMAX_C(432157943248732));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4c337ca791", "%" SCNxMAX, &u.i);
+  MOZ_ASSERT(u.i == UINTMAX_C(327281321873));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedPtr()
+{
+  Input<uintptr_t> u;
+
+  PoisonInput(u);
+  sscanf("57060516", "%" SCNoPTR, &u.i);
+  MOZ_ASSERT(u.i == uintptr_t(reinterpret_cast<void*>(12345678)));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("87654321", "%" SCNuPTR, &u.i);
+  MOZ_ASSERT(u.i == uintptr_t(reinterpret_cast<void*>(87654321)));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4c3a791", "%" SCNxPTR, &u.i);
+  MOZ_ASSERT(u.i == uintptr_t(reinterpret_cast<void*>(0x4c3a791)));
+  MOZ_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsigned()
+{
+  TestScanUnsignedN();
+  TestScanUnsignedLeastN();
+  TestScanUnsignedFastN();
+  TestScanUnsignedMax();
+  TestScanUnsignedPtr();
+}
+
+static void
+TestScan()
+{
+  TestScanSigned();
+  TestScanUnsigned();
+}
+
+#endif /* SHOULD_TEST_SCANF_MACROS */
+
+int
+main()
+{
+  TestPrint();
+#if SHOULD_TEST_SCANF_MACROS
+  TestScan();
+#endif
+  return 0;
+}
--- a/mfbt/tests/TestPoisonArea.cpp
+++ b/mfbt/tests/TestPoisonArea.cpp
@@ -74,34 +74,25 @@
  *    *64*-bit processes on Linux - and we don't even run this code for
  *    64-bit processes.
  *
  * 4. VirtualQuery() does not produce any useful information if
  *    applied to kernel memory - in fact, it doesn't write its output
  *    at all.  Thus, it is not used here.
  */
 
+#include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/NullPtr.h"
 
-// MAP_ANON(YMOUS) is not in any standard, and the C99 PRI* macros are
-// not in C++98.  Add defines as necessary.
-#define __STDC_FORMAT_MACROS
+// MAP_ANON(YMOUS) is not in any standard.  Add defines as necessary.
 #define _GNU_SOURCE 1
 #define _DARWIN_C_SOURCE 1
 
 #include <stddef.h>
 
-#ifndef _WIN32
-#include <inttypes.h>
-#else
-#define PRIxPTR "Ix"
-typedef unsigned int uint32_t;
-// MSVC defines uintptr_t in <crtdefs.h> which is brought in implicitly
-#endif
-
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #ifdef _WIN32
 #include <windows.h>
 #elif defined(__OS2__)
--- a/mfbt/tests/moz.build
+++ b/mfbt/tests/moz.build
@@ -9,16 +9,17 @@ CPP_UNIT_TESTS += [
     'TestBloomFilter.cpp',
     'TestCasting.cpp',
     'TestCeilingFloor.cpp',
     'TestCheckedInt.cpp',
     'TestCountZeroes.cpp',
     'TestEndian.cpp',
     'TestEnumSet.cpp',
     'TestFloatingPoint.cpp',
+    'TestIntegerPrintfMacros.cpp',
     'TestSHA1.cpp',
     'TestTypeTraits.cpp',
     'TestWeakPtr.cpp',
 ]
 
 if not CONFIG['MOZ_ASAN']:
     CPP_UNIT_TESTS += [
         'TestPoisonArea.cpp',
--- a/mozilla-config.h.in
+++ b/mozilla-config.h.in
@@ -3,23 +3,34 @@
  * Do not edit.
  */
 
 #ifndef _MOZILLA_CONFIG_H_
 #define _MOZILLA_CONFIG_H_
 
 @ALLDEFINES@
 
-/* The c99 defining the limit macros (UINT32_MAX for example), says:
- * C++ implementations should define these macros only when __STDC_LIMIT_MACROS
- * is defined before <stdint.h> is included. */
+/*
+ * The c99 defining the limit macros (UINT32_MAX for example), says:
+ *
+ *   C++ implementations should define these macros only when
+ *   __STDC_LIMIT_MACROS is defined before <stdint.h> is included.
+ *
+ * The same also occurs with __STDC_CONSTANT_MACROS for the constant macros
+ * (INT8_C for example) used to specify a literal constant of the proper type,
+ * and with __STDC_FORMAT_MACROS for the format macros (PRId32 for example) used
+ * with the fprintf function family.
+ */
 #define __STDC_LIMIT_MACROS
+#define __STDC_CONSTANT_MACROS
+#define __STDC_FORMAT_MACROS
 
-/* Force-include hunspell_alloc_hooks.h and hunspell_fopen_hooks.h for hunspell,
- * so that we don't need to modify it directly.
+/*
+ * Force-include hunspell_alloc_hooks.h and hunspell_fopen_hooks.h for hunspell,
+ * so that we don't need to modify them directly.
  *
  * HUNSPELL_STATIC is defined in extensions/spellcheck/hunspell/src/Makefile.in,
  * unless --enable-system-hunspell is defined.
  */
 #if defined(HUNSPELL_STATIC)
 #include "hunspell_alloc_hooks.h"
 #include "hunspell_fopen_hooks.h"
 #endif
--- a/security/manager/boot/src/Makefile.in
+++ b/security/manager/boot/src/Makefile.in
@@ -5,16 +5,15 @@
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 EXPORT_LIBRARY	= 1
-DEFINES += -D__STDC_CONSTANT_MACROS
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES	+= \
 		-I$(DIST)/public/nss \
 		$(NULL)