Bug 1334278 - change mozilla::Smprintf to return a UniquePtr; r?froydnj draft
authorTom Tromey <tom@tromey.com>
Fri, 03 Mar 2017 08:17:27 -0700
changeset 568733 41f33e577fe1afae8b9ce59d0bbc03ff6edae158
parent 568732 e5073b47f5c8f7aa8fc2e5578d4fcc6a6c79deed
child 568734 6bc390539e800a48281e77a04cfb727696b9cbf1
push id55961
push userbmo:ttromey@mozilla.com
push dateWed, 26 Apr 2017 14:11:48 +0000
reviewersfroydnj
bugs1334278
milestone55.0a1
Bug 1334278 - change mozilla::Smprintf to return a UniquePtr; r?froydnj Change mozilla::Smprintf and friends to return a UniquePtr, rather than relying on manual memory management. (Though after this patch there are still a handful of spots needing SmprintfFree.) MozReview-Commit-ID: COa4nzIX5qa
chrome/nsChromeRegistry.cpp
dom/plugins/base/nsPluginsDirWin.cpp
dom/webbrowserpersist/nsWebBrowserPersist.cpp
ipc/chromium/src/base/logging.cc
ipc/chromium/src/base/logging.h
ipc/glue/SharedMemoryBasic_mach.mm
js/src/jsprf.cpp
mozglue/misc/Printf.h
netwerk/cookie/nsCookieService.cpp
netwerk/protocol/http/nsHttpHandler.cpp
storage/mozStorageConnection.cpp
storage/mozStorageStatement.cpp
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/profile/nsProfileLock.cpp
toolkit/xre/nsAppRunner.cpp
xpcom/base/Logging.cpp
xpcom/base/nsDebug.h
xpcom/components/ManifestParser.cpp
xpcom/tests/gtest/TestPipes.cpp
xpcom/threads/nsEnvironment.cpp
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -50,23 +50,22 @@ nsChromeRegistry::LogMessage(const char*
 {
   nsCOMPtr<nsIConsoleService> console 
     (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   if (!console)
     return;
 
   va_list args;
   va_start(args, aMsg);
-  char* formatted = mozilla::Vsmprintf(aMsg, args);
+  mozilla::SmprintfPointer formatted = mozilla::Vsmprintf(aMsg, args);
   va_end(args);
   if (!formatted)
     return;
 
-  console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get());
-  mozilla::SmprintfFree(formatted);
+  console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted.get()).get());
 }
 
 void
 nsChromeRegistry::LogMessageWithContext(nsIURI* aURL, uint32_t aLineNumber, uint32_t flags,
                                         const char* aMsg, ...)
 {
   nsresult rv;
 
@@ -75,30 +74,29 @@ nsChromeRegistry::LogMessageWithContext(
 
   nsCOMPtr<nsIScriptError> error
     (do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
   if (!console || !error)
     return;
 
   va_list args;
   va_start(args, aMsg);
-  char* formatted = mozilla::Vsmprintf(aMsg, args);
+  mozilla::SmprintfPointer formatted = mozilla::Vsmprintf(aMsg, args);
   va_end(args);
   if (!formatted)
     return;
 
   nsCString spec;
   if (aURL)
     aURL->GetSpec(spec);
 
-  rv = error->Init(NS_ConvertUTF8toUTF16(formatted),
+  rv = error->Init(NS_ConvertUTF8toUTF16(formatted.get()),
                    NS_ConvertUTF8toUTF16(spec),
                    EmptyString(),
                    aLineNumber, 0, flags, "chrome registration");
-  mozilla::SmprintfFree(formatted);
 
   if (NS_FAILED(rv))
     return;
 
   console->LogMessage(error);
 }
 
 nsChromeRegistry::~nsChromeRegistry()
--- a/dom/plugins/base/nsPluginsDirWin.cpp
+++ b/dom/plugins/base/nsPluginsDirWin.cpp
@@ -98,17 +98,17 @@ static char* GetVersion(void* verbuf)
 
   ::VerQueryValueW(verbuf, L"\\", (void **)&fileInfo, &fileInfoLen);
 
   if (fileInfo) {
     return mozilla::Smprintf("%ld.%ld.%ld.%ld",
                       HIWORD(fileInfo->dwFileVersionMS),
                       LOWORD(fileInfo->dwFileVersionMS),
                       HIWORD(fileInfo->dwFileVersionLS),
-                      LOWORD(fileInfo->dwFileVersionLS));
+                      LOWORD(fileInfo->dwFileVersionLS)).release();
   }
 
   return nullptr;
 }
 
 // Returns a boolean indicating if the key's value contains a string
 // entry equal to "1" or "0". No entry for the key returns false.
 static bool GetBooleanFlag(void* verbuf, const WCHAR* key,
--- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -2023,28 +2023,27 @@ nsWebBrowserPersist::CalculateUniqueFile
         while (true)
         {
             // Make a file name,
             // Foo become foo_001, foo_002, etc.
             // Empty files become _001, _002 etc.
 
             if (base.IsEmpty() || duplicateCounter > 1)
             {
-                char * tmp = mozilla::Smprintf("_%03d", duplicateCounter);
+                SmprintfPointer tmp = mozilla::Smprintf("_%03d", duplicateCounter);
                 NS_ENSURE_TRUE(tmp, NS_ERROR_OUT_OF_MEMORY);
                 if (filename.Length() < kDefaultMaxFilenameLength - 4)
                 {
                     tmpBase = base;
                 }
                 else
                 {
                     base.Mid(tmpBase, 0, base.Length() - 4);
                 }
-                tmpBase.Append(tmp);
-                mozilla::SmprintfFree(tmp);
+                tmpBase.Append(tmp.get());
             }
             else
             {
                 tmpBase = base;
             }
 
             tmpPath.Assign(directory);
             tmpPath.Append(tmpBase);
--- a/ipc/chromium/src/base/logging.cc
+++ b/ipc/chromium/src/base/logging.cc
@@ -3,17 +3,17 @@
 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/logging.h"
 #include "prmem.h"
 #include "base/string_util.h"
 #include "nsXPCOM.h"
-#include "mozilla/Printf.h"
+#include "mozilla/Move.h"
 
 namespace mozilla {
 
 Logger::~Logger()
 {
   LogLevel prlevel = LogLevel::Debug;
   int xpcomlevel = -1;
 
@@ -39,29 +39,27 @@ Logger::~Logger()
     break;
 
   case LOG_FATAL:
     prlevel = LogLevel::Error;
     xpcomlevel = NS_DEBUG_ABORT;
     break;
   }
 
-  MOZ_LOG(gChromiumPRLog, prlevel, ("%s:%i: %s", mFile, mLine, mMsg ? mMsg : "<no message>"));
+  MOZ_LOG(gChromiumPRLog, prlevel, ("%s:%i: %s", mFile, mLine, mMsg ? mMsg.get() : "<no message>"));
   if (xpcomlevel != -1)
-    NS_DebugBreak(xpcomlevel, mMsg, NULL, mFile, mLine);
-
-  mozilla::SmprintfFree(mMsg);
+    NS_DebugBreak(xpcomlevel, mMsg.get(), NULL, mFile, mLine);
 }
 
 void
 Logger::printf(const char* fmt, ...)
 {
   va_list args;
   va_start(args, fmt);
-  mMsg = mozilla::VsmprintfAppend(mMsg, fmt, args);
+  mMsg = mozilla::VsmprintfAppend(mozilla::Move(mMsg), fmt, args);
   va_end(args);
 }
 
 LazyLogModule Logger::gChromiumPRLog("chromium");
 
 mozilla::Logger&
 operator<<(mozilla::Logger& log, const char* s)
 {
--- a/ipc/chromium/src/base/logging.h
+++ b/ipc/chromium/src/base/logging.h
@@ -8,16 +8,17 @@
 #define BASE_LOGGING_H_
 
 #include <string>
 #include <cstring>
 
 #include "base/basictypes.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Logging.h"
+#include "mozilla/Printf.h"
 
 #ifdef NO_CHROMIUM_LOGGING
 #include <sstream>
 #endif
 
 // Replace the Chromium logging code with NSPR-based logging code and
 // some C++ wrappers to emulate std::ostream
 
@@ -34,32 +35,31 @@ enum LogSeverity {
 
 class Logger
 {
 public:
   Logger(LogSeverity severity, const char* file, int line)
     : mSeverity(severity)
     , mFile(file)
     , mLine(line)
-    , mMsg(NULL)
   { }
 
   ~Logger();
 
   // not private so that the operator<< overloads can get to it
   void printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
 
 private:
   static mozilla::LazyLogModule gChromiumPRLog;
 //  static PRLogModuleInfo* GetLog();
 
   LogSeverity mSeverity;
   const char* mFile;
   int mLine;
-  char* mMsg;
+  SmprintfPointer mMsg;
 
   DISALLOW_EVIL_CONSTRUCTORS(Logger);
 };
 
 class LogWrapper
 {
 public:
   LogWrapper(LogSeverity severity, const char* file, int line) :
--- a/ipc/glue/SharedMemoryBasic_mach.mm
+++ b/ipc/glue/SharedMemoryBasic_mach.mm
@@ -26,21 +26,20 @@
 #include "SharedMemoryBasic.h"
 #include "chrome/common/mach_ipc_mac.h"
 
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Printf.h"
 #include "mozilla/StaticMutex.h"
 
 #ifdef DEBUG
-#define LOG_ERROR(str, args...)                 \
-  PR_BEGIN_MACRO                                \
-  char *msg = mozilla::Smprintf(str, ## args);  \
-  NS_WARNING(msg);                              \
-  mozilla::SmprintfFree(msg);                   \
+#define LOG_ERROR(str, args...)                                   \
+  PR_BEGIN_MACRO                                                  \
+  mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ## args); \
+  NS_WARNING(msg.get());                                          \
   PR_END_MACRO
 #else
 #define LOG_ERROR(str, args...) do { /* nothing */ } while(0)
 #endif
 
 #define CHECK_MACH_ERROR(kr, msg)                               \
   PR_BEGIN_MACRO                                                \
   if (kr != KERN_SUCCESS) {                                     \
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -13,40 +13,44 @@
 #include "jsprf.h"
 
 #include "mozilla/Printf.h"
 
 #include "jsalloc.h"
 
 using namespace js;
 
+typedef mozilla::SmprintfPolicyPointer<js::SystemAllocPolicy> JSSmprintfPointer;
+
 JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
-    char* result = mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
+    JSSmprintfPointer result = mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
     va_end(ap);
-    return result;
+    return result.release();
 }
 
 JS_PUBLIC_API(void) JS_smprintf_free(char* mem)
 {
     mozilla::SmprintfFree<js::SystemAllocPolicy>(mem);
 }
 
 JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
-    char* result = mozilla::VsmprintfAppend<js::SystemAllocPolicy>(last, fmt, ap);
+    JSSmprintfPointer result =
+        mozilla::VsmprintfAppend<js::SystemAllocPolicy>(JSSmprintfPointer(last), fmt, ap);
     va_end(ap);
-    return result;
+    return result.release();
 }
 
 JS_PUBLIC_API(char*) JS_vsmprintf(const char* fmt, va_list ap)
 {
-    return mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
+    return mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap).release();
 }
 
 JS_PUBLIC_API(char*) JS_vsprintf_append(char* last, const char* fmt, va_list ap)
 {
-    return mozilla::VsmprintfAppend<js::SystemAllocPolicy>(last, fmt, ap);
+    return mozilla::VsmprintfAppend<js::SystemAllocPolicy>(JSSmprintfPointer(last),
+                                                           fmt, ap).release();
 }
--- a/mozglue/misc/Printf.h
+++ b/mozglue/misc/Printf.h
@@ -50,16 +50,17 @@
 */
 
 #include "mozilla/AllocPolicy.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/SizePrintfMacros.h"
 #include "mozilla/Types.h"
+#include "mozilla/UniquePtr.h"
 
 #include <stdarg.h>
 #include <string.h>
 
 namespace mozilla {
 
 /*
  * This class may be subclassed to provide a way to get the output of
@@ -98,16 +99,36 @@ private:
     bool fill2(const char* src, int srclen, int width, int flags);
     bool fill_n(const char* src, int srclen, int width, int prec, int type, int flags);
     bool cvt_l(long num, int width, int prec, int radix, int type, int flags, const char* hxp);
     bool cvt_ll(int64_t num, int width, int prec, int radix, int type, int flags, const char* hexp);
     bool cvt_f(double d, const char* fmt0, const char* fmt1);
     bool cvt_s(const char* s, int width, int prec, int flags);
 };
 
+namespace detail {
+
+template<typename AllocPolicy = mozilla::MallocAllocPolicy>
+struct AllocPolicyBasedFreePolicy
+{
+  void operator()(const void* ptr) {
+    AllocPolicy policy;
+    policy.free_(const_cast<void*>(ptr));
+  }
+};
+
+}
+
+// The type returned by Smprintf and friends.
+template<typename AllocPolicy>
+using SmprintfPolicyPointer = mozilla::UniquePtr<char, detail::AllocPolicyBasedFreePolicy<AllocPolicy>>;
+
+// The default type if no alloc policy is specified.
+typedef SmprintfPolicyPointer<mozilla::MallocAllocPolicy> SmprintfPointer;
+
 // Used in the implementation of Smprintf et al.
 template<typename AllocPolicy>
 class MOZ_STACK_CLASS SprintfState final : private mozilla::PrintfTarget, private AllocPolicy
 {
  public:
     explicit SprintfState(char* base)
         : mMaxlen(base ? strlen(base) : 0)
         , mBase(base)
@@ -120,18 +141,18 @@ class MOZ_STACK_CLASS SprintfState final
     }
 
     bool vprint(const char* format, va_list ap_list) {
         // The "" here has a single \0 character, which is what we're
         // trying to append.
         return mozilla::PrintfTarget::vprint(format, ap_list) && append("", 1);
     }
 
-    char* release() {
-        char* result = mBase;
+    SmprintfPolicyPointer<AllocPolicy> release() {
+        SmprintfPolicyPointer<AllocPolicy> result(mBase);
         mBase = nullptr;
         return result;
     }
 
  protected:
 
     bool append(const char* sp, size_t len) override {
         ptrdiff_t off;
@@ -168,17 +189,17 @@ class MOZ_STACK_CLASS SprintfState final
 
 /*
 ** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
 ** buffer on success, nullptr on failure. Call AllocPolicy::free_ to release
 ** the memory returned.
 */
 template<typename AllocPolicy = mozilla::MallocAllocPolicy>
 MOZ_FORMAT_PRINTF(1, 2)
-char* Smprintf(const char* fmt, ...)
+SmprintfPolicyPointer<AllocPolicy> Smprintf(const char* fmt, ...)
 {
     SprintfState<AllocPolicy> ss(nullptr);
     va_list ap;
     va_start(ap, fmt);
     bool r = ss.vprint(fmt, ap);
     va_end(ap);
     if (!r) {
         return nullptr;
@@ -190,45 +211,47 @@ char* Smprintf(const char* fmt, ...)
 ** "append" sprintf into a malloc'd buffer. "last" is the last value of
 ** the malloc'd buffer. sprintf will append data to the end of last,
 ** growing it as necessary using realloc. If last is nullptr, SmprintfAppend
 ** 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.
 */
 template<typename AllocPolicy = mozilla::MallocAllocPolicy>
 MOZ_FORMAT_PRINTF(2, 3)
-char* SmprintfAppend(char* last, const char* fmt, ...)
+SmprintfPolicyPointer<AllocPolicy> SmprintfAppend(SmprintfPolicyPointer<AllocPolicy>&& last,
+                                                  const char* fmt, ...)
 {
-    SprintfState<AllocPolicy> ss(last);
+    SprintfState<AllocPolicy> ss(last.release());
     va_list ap;
     va_start(ap, fmt);
     bool r = ss.vprint(fmt, ap);
     va_end(ap);
     if (!r) {
         return nullptr;
     }
     return ss.release();
 }
 
 /*
 ** va_list forms of the above.
 */
 template<typename AllocPolicy = mozilla::MallocAllocPolicy>
-char* Vsmprintf(const char* fmt, va_list ap)
+SmprintfPolicyPointer<AllocPolicy> Vsmprintf(const char* fmt, va_list ap)
 {
     SprintfState<AllocPolicy> ss(nullptr);
     if (!ss.vprint(fmt, ap))
         return nullptr;
     return ss.release();
 }
 
 template<typename AllocPolicy = mozilla::MallocAllocPolicy>
-char* VsmprintfAppend(char* last, const char* fmt, va_list ap)
+SmprintfPolicyPointer<AllocPolicy> VsmprintfAppend(SmprintfPolicyPointer<AllocPolicy>&& last,
+                                                   const char* fmt, va_list ap)
 {
-    SprintfState<AllocPolicy> ss(last);
+    SprintfState<AllocPolicy> ss(last.release());
     if (!ss.vprint(fmt, ap))
         return nullptr;
     return ss.release();
 }
 
 /*
 ** Free the memory allocated, for the caller, by Smprintf.
 */
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -329,20 +329,19 @@ LogSuccess(bool aSetCookie, nsIURI *aHos
   LogSuccess(aSetCookie, aHostURI, aCookieString.get(), aCookie, aReplacing);
 }
 
 #ifdef DEBUG
 #define NS_ASSERT_SUCCESS(res)                                               \
   PR_BEGIN_MACRO                                                             \
   nsresult __rv = res; /* Do not evaluate |res| more than once! */           \
   if (NS_FAILED(__rv)) {                                                     \
-    char *msg = mozilla::Smprintf("NS_ASSERT_SUCCESS(%s) failed with result 0x%" PRIX32, \
+    SmprintfPointer msg = mozilla::Smprintf("NS_ASSERT_SUCCESS(%s) failed with result 0x%" PRIX32, \
                            #res, static_cast<uint32_t>(__rv));               \
-    NS_ASSERTION(NS_SUCCEEDED(__rv), msg);                                   \
-    mozilla::SmprintfFree(msg);                                                    \
+    NS_ASSERTION(NS_SUCCEEDED(__rv), msg.get());                             \
   }                                                                          \
   PR_END_MACRO
 #else
 #define NS_ASSERT_SUCCESS(res) PR_BEGIN_MACRO /* nothing */ PR_END_MACRO
 #endif
 
 /******************************************************************************
  * DBListenerErrorHandler impl:
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -885,22 +885,21 @@ nsHttpHandler::InitUserAgentComponents()
         BOOL isWow64 = FALSE;
         if (!IsWow64Process(GetCurrentProcess(), &isWow64)) {
             isWow64 = FALSE;
         }
         format = isWow64
           ? WNT_BASE "; WOW64"
           : WNT_BASE;
 #endif
-        char *buf = mozilla::Smprintf(format,
-                               info.dwMajorVersion,
-                               info.dwMinorVersion);
+        SmprintfPointer buf = mozilla::Smprintf(format,
+                                                info.dwMajorVersion,
+                                                info.dwMinorVersion);
         if (buf) {
-            mOscpu = buf;
-            mozilla::SmprintfFree(buf);
+            mOscpu = buf.get();
         }
     }
 #elif defined (XP_MACOSX)
 #if defined(__ppc__)
     mOscpu.AssignLiteral("PPC Mac OS X");
 #elif defined(__i386__) || defined(__x86_64__)
     mOscpu.AssignLiteral("Intel Mac OS X");
 #endif
--- a/storage/mozStorageConnection.cpp
+++ b/storage/mozStorageConnection.cpp
@@ -1001,34 +1001,32 @@ Connection::internalClose(sqlite3 *aNati
     sqlite3_stmt *stmt = nullptr;
     while ((stmt = ::sqlite3_next_stmt(aNativeConnection, stmt))) {
       MOZ_LOG(gStorageLog, LogLevel::Debug,
              ("Auto-finalizing SQL statement '%s' (%p)",
               ::sqlite3_sql(stmt),
               stmt));
 
 #ifdef DEBUG
-      char *msg = ::mozilla::Smprintf("SQL statement '%s' (%p) should have been finalized before closing the connection",
-                               ::sqlite3_sql(stmt),
-                               stmt);
-      NS_WARNING(msg);
-      ::mozilla::SmprintfFree(msg);
-      msg = nullptr;
+      {
+        SmprintfPointer msg = ::mozilla::Smprintf("SQL statement '%s' (%p) should have been finalized before closing the connection",
+                                           ::sqlite3_sql(stmt),
+                                           stmt);
+        NS_WARNING(msg.get());
+      }
 #endif // DEBUG
 
       srv = ::sqlite3_finalize(stmt);
 
 #ifdef DEBUG
       if (srv != SQLITE_OK) {
-        msg = ::mozilla::Smprintf("Could not finalize SQL statement '%s' (%p)",
-                           ::sqlite3_sql(stmt),
-                           stmt);
-        NS_WARNING(msg);
-        ::mozilla::SmprintfFree(msg);
-        msg = nullptr;
+        SmprintfPointer msg = ::mozilla::Smprintf("Could not finalize SQL statement '%s' (%p)",
+                                           ::sqlite3_sql(stmt),
+                                           stmt);
+        NS_WARNING(msg.get());
       }
 #endif // DEBUG
 
       // Ensure that the loop continues properly, whether closing has succeeded
       // or not.
       if (srv == SQLITE_OK) {
         stmt = nullptr;
       }
@@ -1811,22 +1809,21 @@ Connection::rollbackTransactionInternal(
 }
 
 NS_IMETHODIMP
 Connection::CreateTable(const char *aTableName,
                         const char *aTableSchema)
 {
   if (!mDBConn) return NS_ERROR_NOT_INITIALIZED;
 
-  char *buf = ::mozilla::Smprintf("CREATE TABLE %s (%s)", aTableName, aTableSchema);
+  SmprintfPointer buf = ::mozilla::Smprintf("CREATE TABLE %s (%s)", aTableName, aTableSchema);
   if (!buf)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  int srv = executeSql(mDBConn, buf);
-  ::mozilla::SmprintfFree(buf);
+  int srv = executeSql(mDBConn, buf.get());
 
   return convertResultCode(srv);
 }
 
 NS_IMETHODIMP
 Connection::CreateFunction(const nsACString &aFunctionName,
                            int32_t aNumArguments,
                            mozIStorageFunction *aFunction)
--- a/storage/mozStorageStatement.cpp
+++ b/storage/mozStorageStatement.cpp
@@ -377,38 +377,36 @@ Statement::internalFinalize(bool aDestru
     //
     // The database connection is either closed or closing. The sqlite
     // statement has either been finalized already by the connection
     // or is about to be finalized by the connection.
     //
     // Finalizing it here would be useless and segfaultish.
     //
 
-    char *msg = ::mozilla::Smprintf("SQL statement (%p) should have been finalized"
+    SmprintfPointer msg = ::mozilla::Smprintf("SQL statement (%p) should have been finalized"
       " before garbage-collection. For more details on this statement, set"
       " NSPR_LOG_MESSAGES=mozStorage:5 .",
       mDBStatement);
 
     //
     // Note that we can't display the statement itself, as the data structure
     // is not valid anymore. However, the address shown here should help
     // developers correlate with the more complete debug message triggered
     // by AsyncClose().
     //
 
 #if 0
     // Deactivate the warning until we have fixed the exising culprit
     // (see bug 914070).
-    NS_WARNING(msg);
+    NS_WARNING(msg.get());
 #endif // 0
 
     // Use %s so we aren't exposing random strings to printf interpolation.
-    MOZ_LOG(gStorageLog, LogLevel::Warning, ("%s", msg));
-
-    ::mozilla::SmprintfFree(msg);
+    MOZ_LOG(gStorageLog, LogLevel::Warning, ("%s", msg.get()));
   }
 
 #endif
 
   mDBStatement = nullptr;
 
   if (mAsyncStatement) {
     // If the destructor called us, there are no pending async statements (they
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -3537,17 +3537,17 @@ OOPInit()
     childProcessTmpDir = CreatePathFromFile(tmpDir);
   }
 # endif // defined(MOZ_CONTENT_SANDBOX)
 #endif // (defined(XP_WIN) || defined(XP_MACOSX))
 
 #if defined(XP_WIN)
   childCrashNotifyPipe =
     mozilla::Smprintf("\\\\.\\pipe\\gecko-crash-server-pipe.%i",
-               static_cast<int>(::GetCurrentProcessId()));
+               static_cast<int>(::GetCurrentProcessId())).release();
 
   const std::wstring dumpPath = gExceptionHandler->dump_path();
   crashServer = new CrashGenerationServer(
     std::wstring(NS_ConvertASCIItoUTF16(childCrashNotifyPipe).get()),
     nullptr,                    // default security attributes
     nullptr, nullptr,           // we don't care about process connect here
     OnChildProcessDumpRequested, nullptr,
     nullptr, nullptr,           // we don't care about process exit here
@@ -3567,17 +3567,17 @@ OOPInit()
     OnChildProcessDumpRequested, nullptr,
     nullptr, nullptr,           // we don't care about process exit here
     true,
     &dumpPath);
 
 #elif defined(XP_MACOSX)
   childCrashNotifyPipe =
     mozilla::Smprintf("gecko-crash-server-pipe.%i",
-               static_cast<int>(getpid()));
+               static_cast<int>(getpid())).release();
   const std::string dumpPath = gExceptionHandler->dump_path();
 
   crashServer = new CrashGenerationServer(
     childCrashNotifyPipe,
     nullptr,
     nullptr,
     OnChildProcessDumpRequested, nullptr,
     nullptr, nullptr,
--- a/toolkit/profile/nsProfileLock.cpp
+++ b/toolkit/profile/nsProfileLock.cpp
@@ -347,42 +347,39 @@ nsresult nsProfileLock::LockWithSymlink(
     {
         char netdbbuf[PR_NETDB_BUF_SIZE];
         PRHostEnt hostent;
         status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent);
         if (status == PR_SUCCESS)
             memcpy(&inaddr, hostent.h_addr, sizeof inaddr);
     }
 
-    char *signature =
+    mozilla::SmprintfPointer signature =
         mozilla::Smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "",
                    (unsigned long)getpid());
     const char *fileName = lockFilePath.get();
     int symlink_rv, symlink_errno = 0, tries = 0;
 
     // use ns4.x-compatible symlinks if the FS supports them
-    while ((symlink_rv = symlink(signature, fileName)) < 0)
+    while ((symlink_rv = symlink(signature.get(), fileName)) < 0)
     {
         symlink_errno = errno;
         if (symlink_errno != EEXIST)
             break;
 
         if (!IsSymlinkStaleLock(&inaddr, fileName, aHaveFcntlLock))
             break;
 
         // Lock seems to be bogus: try to claim it.  Give up after a large
         // number of attempts (100 comes from the 4.x codebase).
         (void) unlink(fileName);
         if (++tries > 100)
             break;
     }
 
-    mozilla::SmprintfFree(signature);
-    signature = nullptr;
-
     if (symlink_rv == 0)
     {
         // We exclusively created the symlink: record its name for eventual
         // unlock-via-unlink.
         rv = NS_OK;
         mPidLockFileName = strdup(fileName);
         if (mPidLockFileName)
         {
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -430,35 +430,34 @@ static void UnexpectedExit() {
  *        printf-style format string followed by arguments.
  */
 static MOZ_FORMAT_PRINTF(2, 3) void Output(bool isError, const char *fmt, ... )
 {
   va_list ap;
   va_start(ap, fmt);
 
 #if defined(XP_WIN) && !MOZ_WINCONSOLE
-  char *msg = mozilla::Vsmprintf(fmt, ap);
+  SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
   if (msg)
   {
     UINT flags = MB_OK;
     if (isError)
       flags |= MB_ICONERROR;
     else
       flags |= MB_ICONINFORMATION;
 
     wchar_t wide_msg[1024];
     MultiByteToWideChar(CP_ACP,
                         0,
-                        msg,
+                        msg.get(),
                         -1,
                         wide_msg,
                         sizeof(wide_msg) / sizeof(wchar_t));
 
     MessageBoxW(nullptr, wide_msg, L"XULRunner", flags);
-    mozilla::SmprintfFree(msg);
   }
 #else
   vfprintf(stderr, fmt, ap);
 #endif
 
   va_end(ap);
 }
 
@@ -4410,19 +4409,18 @@ XREMain::XRE_mainRun()
   }
 
 #ifdef XP_WIN
   // Hack to sync up the various environment storages. XUL_APP_FILE is special
   // in that it comes from a different CRT (firefox.exe's static-linked copy).
   // Ugly details in http://bugzil.la/1175039#c27
   char appFile[MAX_PATH];
   if (GetEnvironmentVariableA("XUL_APP_FILE", appFile, sizeof(appFile))) {
-    char* saved = mozilla::Smprintf("XUL_APP_FILE=%s", appFile);
-    PR_SetEnv(saved);
-    mozilla::SmprintfFree(saved);
+    SmprintfPointer saved = mozilla::Smprintf("XUL_APP_FILE=%s", appFile);
+    PR_SetEnv(saved.get());
   }
 #endif
 
   SaveStateForAppInitiatedRestart();
 
   // clear out any environment variables which may have been set
   // during the relaunch process now that we know we won't be relaunching.
   SaveToEnv("XRE_PROFILE_PATH=");
--- a/xpcom/base/Logging.cpp
+++ b/xpcom/base/Logging.cpp
@@ -346,33 +346,35 @@ public:
   }
 
   void Print(const char* aName, LogLevel aLevel, const char* aFmt, va_list aArgs)
   {
     const size_t kBuffSize = 1024;
     char buff[kBuffSize];
 
     char* buffToWrite = buff;
+    SmprintfPointer allocatedBuff;
 
     va_list argsCopy;
     va_copy(argsCopy, aArgs);
     int charsWritten = VsprintfLiteral(buff, aFmt, argsCopy);
     va_end(argsCopy);
 
     if (charsWritten < 0) {
       // Print out at least something.  We must copy to the local buff,
       // can't just assign aFmt to buffToWrite, since when
       // buffToWrite != buff, we try to release it.
       MOZ_ASSERT(false, "Probably incorrect format string in LOG?");
       strncpy(buff, aFmt, kBuffSize - 1);
       buff[kBuffSize - 1] = '\0';
       charsWritten = strlen(buff);
     } else if (static_cast<size_t>(charsWritten) >= kBuffSize - 1) {
       // We may have maxed out, allocate a buffer instead.
-      buffToWrite = mozilla::Vsmprintf(aFmt, aArgs);
+      allocatedBuff = mozilla::Vsmprintf(aFmt, aArgs);
+      buffToWrite = allocatedBuff.get();
       charsWritten = strlen(buffToWrite);
     }
 
     // Determine if a newline needs to be appended to the message.
     const char* newline = "";
     if (charsWritten == 0 || buffToWrite[charsWritten - 1] != '\n') {
       newline = "\n";
     }
@@ -422,20 +424,16 @@ public:
           currentThreadName, ToLogStr(aLevel),
           aName, buffToWrite, newline);
     }
 
     if (mIsSync) {
       fflush(out);
     }
 
-    if (buffToWrite != buff) {
-      mozilla::SmprintfFree(buffToWrite);
-    }
-
     if (mRotate > 0 && outFile) {
       int32_t fileSize = ftell(out);
       if (fileSize > mRotate) {
         uint32_t fileNum = outFile->Num();
 
         uint32_t nextFileNum = fileNum + 1;
         if (nextFileNum >= kRotateFilesNumber) {
           nextFileNum = 0;
--- a/xpcom/base/nsDebug.h
+++ b/xpcom/base/nsDebug.h
@@ -286,28 +286,26 @@ inline void MOZ_PretendNoReturn()
 
 /******************************************************************************
 ** Macros for checking results
 ******************************************************************************/
 
 #if defined(DEBUG) && !defined(XPCOM_GLUE_AVOID_NSPR)
 
 #define NS_ENSURE_SUCCESS_BODY(res, ret)                                  \
-    char *msg = mozilla::Smprintf("NS_ENSURE_SUCCESS(%s, %s) failed with "       \
+    mozilla::SmprintfPointer msg = mozilla::Smprintf("NS_ENSURE_SUCCESS(%s, %s) failed with " \
                            "result 0x%" PRIX32, #res, #ret,               \
                            static_cast<uint32_t>(__rv));                  \
-    NS_WARNING(msg);                                                      \
-    mozilla::SmprintfFree(msg);
+    NS_WARNING(msg.get());
 
 #define NS_ENSURE_SUCCESS_BODY_VOID(res)                                  \
-    char *msg = mozilla::Smprintf("NS_ENSURE_SUCCESS_VOID(%s) failed with "      \
+    mozilla::SmprintfPointer msg = mozilla::Smprintf("NS_ENSURE_SUCCESS_VOID(%s) failed with " \
                            "result 0x%" PRIX32, #res,                     \
                            static_cast<uint32_t>(__rv));                  \
-    NS_WARNING(msg);                                                      \
-    mozilla::SmprintfFree(msg);
+    NS_WARNING(msg.get());
 
 #else
 
 #define NS_ENSURE_SUCCESS_BODY(res, ret)                                  \
     NS_WARNING("NS_ENSURE_SUCCESS(" #res ", " #ret ") failed");
 
 #define NS_ENSURE_SUCCESS_BODY_VOID(res)                                  \
     NS_WARNING("NS_ENSURE_SUCCESS_VOID(" #res ") failed");
--- a/xpcom/components/ManifestParser.cpp
+++ b/xpcom/components/ManifestParser.cpp
@@ -131,28 +131,16 @@ static const ManifestDirective kParsingT
 static const char kWhitespace[] = "\t ";
 
 static bool
 IsNewline(char aChar)
 {
   return aChar == '\n' || aChar == '\r';
 }
 
-namespace {
-struct SmprintfFreePolicy
-{
-  void operator()(char* ptr) {
-    mozilla::SmprintfFree(ptr);
-  }
-};
-
-typedef mozilla::UniquePtr<char, SmprintfFreePolicy> SmprintfPointer;
-
-} // namespace
-
 /**
  * If we are pre-loading XPTs, this method may do nothing because the
  * console service is not initialized.
  */
 void
 LogMessage(const char* aMsg, ...)
 {
   if (!nsComponentManagerImpl::gComponentManager) {
--- a/xpcom/tests/gtest/TestPipes.cpp
+++ b/xpcom/tests/gtest/TestPipes.cpp
@@ -109,27 +109,26 @@ TestPipe(nsIInputStream* in, nsIOutputSt
     nsCOMPtr<nsIThread> thread;
     rv = NS_NewNamedThread("TestPipe", getter_AddRefs(thread), receiver);
     if (NS_FAILED(rv)) return rv;
 
     uint32_t total = 0;
     PRIntervalTime start = PR_IntervalNow();
     for (uint32_t i = 0; i < ITERATIONS; i++) {
         uint32_t writeCount;
-        char *buf = mozilla::Smprintf("%d %s", i, kTestPattern);
-        uint32_t len = strlen(buf);
-        rv = WriteAll(out, buf, len, &writeCount);
+        SmprintfPointer buf = mozilla::Smprintf("%d %s", i, kTestPattern);
+        uint32_t len = strlen(buf.get());
+        rv = WriteAll(out, buf.get(), len, &writeCount);
         if (gTrace) {
             printf("wrote: ");
             for (uint32_t j = 0; j < writeCount; j++) {
-                putc(buf[j], stdout);
+              putc(buf.get()[j], stdout);
             }
             printf("\n");
         }
-        mozilla::SmprintfFree(buf);
         if (NS_FAILED(rv)) return rv;
         total += writeCount;
     }
     rv = out->Close();
     if (NS_FAILED(rv)) return rv;
 
     PRIntervalTime end = PR_IntervalNow();
 
@@ -227,28 +226,27 @@ TestShortWrites(nsIInputStream* in, nsIO
     nsCOMPtr<nsIThread> thread;
     rv = NS_NewNamedThread("TestShortWrites", getter_AddRefs(thread),
                            receiver);
     if (NS_FAILED(rv)) return rv;
 
     uint32_t total = 0;
     for (uint32_t i = 0; i < ITERATIONS; i++) {
         uint32_t writeCount;
-        char* buf = mozilla::Smprintf("%d %s", i, kTestPattern);
-        uint32_t len = strlen(buf);
+        SmprintfPointer buf = mozilla::Smprintf("%d %s", i, kTestPattern);
+        uint32_t len = strlen(buf.get());
         len = len * rand() / RAND_MAX;
         len = std::min(1u, len);
-        rv = WriteAll(out, buf, len, &writeCount);
+        rv = WriteAll(out, buf.get(), len, &writeCount);
         if (NS_FAILED(rv)) return rv;
         EXPECT_EQ(writeCount, len);
         total += writeCount;
 
         if (gTrace)
-            printf("wrote %d bytes: %s\n", writeCount, buf);
-        mozilla::SmprintfFree(buf);
+          printf("wrote %d bytes: %s\n", writeCount, buf.get());
         //printf("calling Flush\n");
         out->Flush();
         //printf("calling WaitForReceipt\n");
 
 #ifdef DEBUG
         const uint32_t received =
           receiver->WaitForReceipt(writeCount);
         EXPECT_EQ(received, writeCount);
@@ -340,29 +338,27 @@ TEST(Pipes, ChainedPipes)
     nsCOMPtr<nsIThread> receiverThread;
     rv = NS_NewNamedThread("ChainedPipeRecv", getter_AddRefs(receiverThread),
                            receiver);
     if (NS_FAILED(rv)) return;
 
     uint32_t total = 0;
     for (uint32_t i = 0; i < ITERATIONS; i++) {
         uint32_t writeCount;
-        char* buf = mozilla::Smprintf("%d %s", i, kTestPattern);
-        uint32_t len = strlen(buf);
+        SmprintfPointer buf = mozilla::Smprintf("%d %s", i, kTestPattern);
+        uint32_t len = strlen(buf.get());
         len = len * rand() / RAND_MAX;
         len = std::max(1u, len);
-        rv = WriteAll(out1, buf, len, &writeCount);
+        rv = WriteAll(out1, buf.get(), len, &writeCount);
         if (NS_FAILED(rv)) return;
         EXPECT_EQ(writeCount, len);
         total += writeCount;
 
         if (gTrace)
-            printf("wrote %d bytes: %s\n", writeCount, buf);
-
-        mozilla::SmprintfFree(buf);
+            printf("wrote %d bytes: %s\n", writeCount, buf.get());
     }
     if (gTrace) {
         printf("wrote total of %d bytes\n", total);
     }
     rv = out1->Close();
     if (NS_FAILED(rv)) return;
 
     thread->Shutdown();
--- a/xpcom/threads/nsEnvironment.cpp
+++ b/xpcom/threads/nsEnvironment.cpp
@@ -140,24 +140,24 @@ nsEnvironment::Set(const nsAString& aNam
     return NS_ERROR_UNEXPECTED;
   }
 
   EnvEntryType* entry = gEnvHash->PutEntry(nativeName.get());
   if (!entry) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  char* newData = mozilla::Smprintf("%s=%s",
-                             nativeName.get(),
-                             nativeVal.get());
+  SmprintfPointer newData = mozilla::Smprintf("%s=%s",
+                                              nativeName.get(),
+                                              nativeVal.get());
   if (!newData) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  PR_SetEnv(newData);
+  PR_SetEnv(newData.get());
   if (entry->mData) {
     mozilla::SmprintfFree(entry->mData);
   }
-  entry->mData = newData;
+  entry->mData = newData.release();
   return NS_OK;
 }