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 158227 a90c62555235c1525c3134ec030736be5c51de6a
parent 158226 7d8b339221780205a0f16a83b159e23eabf81670
child 158228 75556cd1a5234a95e0a542dc5122983642678881
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersespindola
bugs730805
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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)