Bug 1334279 - mark vsprintf-likes with MOZ_FORMAT_PRINTF; r?froydnj draft
authorTom Tromey <tom@tromey.com>
Thu, 04 May 2017 12:10:19 -0600
changeset 574262 6c5a3f23a59bab2ec270328284ebd898c1100f0a
parent 574221 b2bec2797b6d967c762e4ff2423c55702e5a862d
child 627527 98124aa6f039587a81f2d1b5e3c9544e82207612
push id57634
push userbmo:ttromey@mozilla.com
push dateMon, 08 May 2017 15:46:29 +0000
reviewersfroydnj
bugs1334279
milestone55.0a1
Bug 1334279 - mark vsprintf-likes with MOZ_FORMAT_PRINTF; r?froydnj This annotates vsprintf-like functions with MOZ_FORMAT_PRINTF. This may provide some minimal checking of such calls (the GCC docs say that it checks for the string for "consistency"); but in any case shouldn't hurt. MozReview-Commit-ID: HgnAK1LiorE
dom/canvas/WebGLContext.h
js/src/jit/JitSpewer.h
js/src/jit/MIRGenerator.h
js/src/jit/arm/Assembler-arm.h
js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h
js/src/jscntxt.h
js/src/jsprf.h
js/src/vm/Printer.h
js/src/wasm/AsmJS.cpp
mfbt/Attributes.h
mfbt/Sprintf.h
mozglue/misc/Printf.h
xpcom/base/Logging.cpp
xpcom/base/Logging.h
xpcom/base/nsDebug.h
xpcom/string/nsTSubstring.h
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -2049,17 +2049,17 @@ protected:
     // because WebGLContext objects only go away during GC, which shouldn't happen too frequently.
     // If in the future GC becomes much more frequent, we may have to revisit then (maybe use a timer).
     ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper;
 #endif
 
 public:
     // console logging helpers
     void GenerateWarning(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
-    void GenerateWarning(const char* fmt, va_list ap);
+    void GenerateWarning(const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
 
     void GeneratePerfWarning(const char* fmt, ...) const MOZ_FORMAT_PRINTF(2, 3);
 
 public:
     UniquePtr<webgl::FormatUsageAuthority> mFormatUsage;
 
     virtual UniquePtr<webgl::FormatUsageAuthority>
     CreateFormatUsage(gl::GLContext* gl) const = 0;
--- a/js/src/jit/JitSpewer.h
+++ b/js/src/jit/JitSpewer.h
@@ -178,19 +178,19 @@ class JitSpewIndent
 };
 
 void JitSpew(JitSpewChannel channel, const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
 void JitSpewStart(JitSpewChannel channel, const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
 void JitSpewCont(JitSpewChannel channel, const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
 void JitSpewFin(JitSpewChannel channel);
 void JitSpewHeader(JitSpewChannel channel);
 bool JitSpewEnabled(JitSpewChannel channel);
-void JitSpewVA(JitSpewChannel channel, const char* fmt, va_list ap);
-void JitSpewStartVA(JitSpewChannel channel, const char* fmt, va_list ap);
-void JitSpewContVA(JitSpewChannel channel, const char* fmt, va_list ap);
+void JitSpewVA(JitSpewChannel channel, const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
+void JitSpewStartVA(JitSpewChannel channel, const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
+void JitSpewContVA(JitSpewChannel channel, const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
 void JitSpewDef(JitSpewChannel channel, const char* str, MDefinition* def);
 
 void EnableChannel(JitSpewChannel channel);
 void DisableChannel(JitSpewChannel channel);
 void EnableIonDebugSyncLogging();
 void EnableIonDebugAsyncLogging();
 
 #else
@@ -248,17 +248,18 @@ static inline void JitSpewCheckArguments
 
 static inline void JitSpewFin(JitSpewChannel channel)
 { }
 
 static inline void JitSpewHeader(JitSpewChannel channel)
 { }
 static inline bool JitSpewEnabled(JitSpewChannel channel)
 { return false; }
-static inline void JitSpewVA(JitSpewChannel channel, const char* fmt, va_list ap)
+static inline MOZ_FORMAT_PRINTF(2, 0)
+void JitSpewVA(JitSpewChannel channel, const char* fmt, va_list ap)
 { }
 static inline void JitSpewDef(JitSpewChannel channel, const char* str, MDefinition* def)
 { }
 
 static inline void EnableChannel(JitSpewChannel)
 { }
 static inline void DisableChannel(JitSpewChannel)
 { }
--- a/js/src/jit/MIRGenerator.h
+++ b/js/src/jit/MIRGenerator.h
@@ -72,17 +72,17 @@ class MIRGenerator
 
     // Set an error state and prints a message. Returns false so errors can be
     // propagated up.
     mozilla::GenericErrorResult<AbortReason> abort(AbortReason r);
     mozilla::GenericErrorResult<AbortReason>
     abort(AbortReason r, const char* message, ...) MOZ_FORMAT_PRINTF(3, 4);
 
     mozilla::GenericErrorResult<AbortReason>
-    abortFmt(AbortReason r, const char* message, va_list ap);
+    abortFmt(AbortReason r, const char* message, va_list ap) MOZ_FORMAT_PRINTF(3, 0);
 
     // Collect the evaluation result of phases after IonBuilder, such that
     // off-thread compilation can report what error got encountered.
     void setOffThreadStatus(AbortReasonOr<Ok> result) {
         MOZ_ASSERT(offThreadStatus_.isOk());
         offThreadStatus_ = result;
     }
     AbortReasonOr<Ok> getOffThreadStatus() const {
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -1312,17 +1312,17 @@ class Assembler : public AssemblerShared
     uint32_t spewNext_;
     Sprinter* printer_;
 
     bool spewDisabled();
     uint32_t spewResolve(Label* l);
     uint32_t spewProbe(Label* l);
     uint32_t spewDefine(Label* l);
     void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
-    void spew(const char* fmt, va_list args);
+    void spew(const char* fmt, va_list args) MOZ_FORMAT_PRINTF(2, 0);
 #endif
 
   public:
     // For the alignment fill use NOP: 0x0320f000 or (Always | InstNOP::NopInst).
     // For the nopFill use a branch to the next instruction: 0xeaffffff.
     Assembler()
       : m_buffer(1, 1, 8, GetPoolMaxOffset(), 8, 0xe320f000, 0xeaffffff, GetNopFill()),
 #ifdef JS_DISASM_ARM
--- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h
+++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h
@@ -218,16 +218,16 @@ namespace jit {
                 va_start(va, fmt);
                 spew(fmt, va);
                 va_end(va);
             }
 #endif
         }
 
 #ifdef JS_JITSPEW
-        MOZ_COLD void spew(const char* fmt, va_list va);
+        MOZ_COLD void spew(const char* fmt, va_list va) MOZ_FORMAT_PRINTF(2, 0);
 #endif
     };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x86_shared_AssemblerBuffer_x86_shared_h */
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1019,17 +1019,17 @@ enum ErrorArgumentsType {
  * Defined in SelfHosting.cpp.
  */
 JSFunction*
 SelfHostedFunction(JSContext* cx, HandlePropertyName propName);
 
 #ifdef va_start
 extern bool
 ReportErrorVA(JSContext* cx, unsigned flags, const char* format,
-              ErrorArgumentsType argumentsType, va_list ap);
+              ErrorArgumentsType argumentsType, va_list ap) MOZ_FORMAT_PRINTF(3, 0);
 
 extern bool
 ReportErrorNumberVA(JSContext* cx, unsigned flags, JSErrorCallback callback,
                     void* userRef, const unsigned errorNumber,
                     ErrorArgumentsType argumentsType, va_list ap);
 
 extern bool
 ReportErrorNumberUCArray(JSContext* cx, unsigned flags, JSErrorCallback callback,
--- a/js/src/jsprf.h
+++ b/js/src/jsprf.h
@@ -21,13 +21,15 @@ extern JS_PUBLIC_API(JS::UniqueChars) JS
     MOZ_FORMAT_PRINTF(1, 2);
 
 extern JS_PUBLIC_API(void) JS_smprintf_free(char* mem);
 
 extern JS_PUBLIC_API(JS::UniqueChars) JS_sprintf_append(JS::UniqueChars&& last,
                                                         const char* fmt, ...)
      MOZ_FORMAT_PRINTF(2, 3);
 
-extern JS_PUBLIC_API(JS::UniqueChars) JS_vsmprintf(const char* fmt, va_list ap);
+extern JS_PUBLIC_API(JS::UniqueChars) JS_vsmprintf(const char* fmt, va_list ap)
+    MOZ_FORMAT_PRINTF(1, 0);
 extern JS_PUBLIC_API(JS::UniqueChars) JS_vsprintf_append(JS::UniqueChars&& last,
-                                                         const char* fmt, va_list ap);
+                                                         const char* fmt, va_list ap)
+    MOZ_FORMAT_PRINTF(2, 0);
 
 #endif /* jsprf_h */
--- a/js/src/vm/Printer.h
+++ b/js/src/vm/Printer.h
@@ -40,17 +40,17 @@ class GenericPrinter
     virtual bool put(const char* s, size_t len) = 0;
 
     inline bool put(const char* s) {
         return put(s, strlen(s));
     }
 
     // Prints a formatted string into the buffer.
     bool printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
-    bool vprintf(const char* fmt, va_list ap);
+    bool vprintf(const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
 
     // Report that a string operation failed to get the memory it requested. The
     // first call to this function calls JS_ReportOutOfMemory, and sets this
     // Sprinter's outOfMemory flag; subsequent calls do nothing.
     virtual void reportOutOfMemory();
 
     // Return true if this Sprinter ran out of memory.
     virtual bool hadOutOfMemory() const;
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -2263,17 +2263,17 @@ class MOZ_STACK_CLASS ModuleValidator
     bool failCurrentOffset(const char* str) {
         return failOffset(tokenStream().currentToken().pos.begin, str);
     }
 
     bool fail(ParseNode* pn, const char* str) {
         return failOffset(pn->pn_pos.begin, str);
     }
 
-    bool failfVAOffset(uint32_t offset, const char* fmt, va_list ap) {
+    bool failfVAOffset(uint32_t offset, const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(3, 0) {
         MOZ_ASSERT(!hasAlreadyFailed());
         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
         MOZ_ASSERT(fmt);
         errorOffset_ = offset;
         errorString_ = JS_vsmprintf(fmt, ap);
         return false;
     }
 
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -622,16 +622,19 @@
  * So, for a simple case like:
  *   void print_something (int whatever, const char *fmt, ...);
  * The corresponding annotation would be
  *   MOZ_FORMAT_PRINTF(2, 3)
  * However, if "print_something" were a non-static member function,
  * then the annotation would be:
  *   MOZ_FORMAT_PRINTF(3, 4)
  *
+ * The second argument should be 0 for vprintf-like functions; that
+ * is, those taking a va_list argument.
+ *
  * Note that the checking is limited to standards-conforming
  * printf-likes, and in particular this should not be used for
  * PR_snprintf and friends, which are "printf-like" but which assign
  * different meanings to the various formats.
  *
  * MinGW requires special handling due to different format specifiers
  * on different platforms. The macro __MINGW_PRINTF_FORMAT maps to
  * either gnu_printf or ms_printf depending on where we are compiling
--- a/mfbt/Sprintf.h
+++ b/mfbt/Sprintf.h
@@ -13,16 +13,17 @@
 #include <stdarg.h>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 
 #ifdef __cplusplus
 
 template <size_t N>
+MOZ_FORMAT_PRINTF(2, 0)
 int VsprintfLiteral(char (&buffer)[N], const char* format, va_list args)
 {
     MOZ_ASSERT(format != buffer);
     int result = vsnprintf(buffer, N, format, args);
     buffer[N - 1] = '\0';
     return result;
 }
 
--- a/mozglue/misc/Printf.h
+++ b/mozglue/misc/Printf.h
@@ -68,17 +68,17 @@ namespace mozilla {
  */
 class PrintfTarget
 {
 public:
     /* The Printf-like interface.  */
     bool MFBT_API print(const char* format, ...) MOZ_FORMAT_PRINTF(2, 3);
 
     /* The Vprintf-like interface.  */
-    bool MFBT_API vprint(const char* format, va_list);
+    bool MFBT_API vprint(const char* format, va_list) MOZ_FORMAT_PRINTF(2, 0);
 
 protected:
     MFBT_API PrintfTarget();
     virtual ~PrintfTarget() { }
 
     /* Subclasses override this.  It is called when more output is
        available.  It may be called with len==0.  This should return
        true on success, or false on failure.  */
@@ -135,17 +135,17 @@ class MOZ_STACK_CLASS SprintfState final
         , mCur(base ? base + mMaxlen : 0)
     {
     }
 
     ~SprintfState() {
         this->free_(mBase);
     }
 
-    bool vprint(const char* format, va_list ap_list) {
+    bool vprint(const char* format, va_list ap_list) MOZ_FORMAT_PRINTF(2, 0) {
         // The "" here has a single \0 character, which is what we're
         // trying to append.
         return mozilla::PrintfTarget::vprint(format, ap_list) && append("", 1);
     }
 
     SmprintfPolicyPointer<AllocPolicy> release() {
         SmprintfPolicyPointer<AllocPolicy> result(mBase);
         mBase = nullptr;
@@ -229,25 +229,27 @@ SmprintfPolicyPointer<AllocPolicy> Smpri
     }
     return ss.release();
 }
 
 /*
 ** va_list forms of the above.
 */
 template<typename AllocPolicy = mozilla::MallocAllocPolicy>
+MOZ_FORMAT_PRINTF(1, 0)
 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>
+MOZ_FORMAT_PRINTF(2, 0)
 SmprintfPolicyPointer<AllocPolicy> VsmprintfAppend(SmprintfPolicyPointer<AllocPolicy>&& last,
                                                    const char* fmt, va_list ap)
 {
     SprintfState<AllocPolicy> ss(last.release());
     if (!ss.vprint(fmt, ap))
         return nullptr;
     return ss.release();
 }
--- a/xpcom/base/Logging.cpp
+++ b/xpcom/base/Logging.cpp
@@ -341,16 +341,17 @@ public:
       module = new LogModule(aName, LogLevel::Disabled);
       mModules.Put(aName, module);
     }
 
     return module;
   }
 
   void Print(const char* aName, LogLevel aLevel, const char* aFmt, va_list aArgs)
+    MOZ_FORMAT_PRINTF(4, 0)
   {
     const size_t kBuffSize = 1024;
     char buff[kBuffSize];
 
     char* buffToWrite = buff;
     SmprintfPointer allocatedBuff;
 
     va_list argsCopy;
--- a/xpcom/base/Logging.h
+++ b/xpcom/base/Logging.h
@@ -114,17 +114,17 @@ public:
   /**
    * Sets the log module's level.
    */
   void SetLevel(LogLevel level) { mLevel = level; }
 
   /**
    * Print a log message for this module.
    */
-  void Printv(LogLevel aLevel, const char* aFmt, va_list aArgs) const;
+  void Printv(LogLevel aLevel, const char* aFmt, va_list aArgs) const MOZ_FORMAT_PRINTF(3, 0);
 
   /**
    * Retrieves the module name.
    */
   const char* Name() const { return mName; }
 
 private:
   friend class LogModuleManager;
--- a/xpcom/base/nsDebug.h
+++ b/xpcom/base/nsDebug.h
@@ -388,17 +388,17 @@ extern "C" {
  *  - on Windows, if a debugger is present, it calls OutputDebugString
  *    in *addition* to writing to stderr
  */
 void printf_stderr(const char* aFmt, ...) MOZ_FORMAT_PRINTF(1, 2);
 
 /**
  * Same as printf_stderr, but taking va_list instead of varargs
  */
-void vprintf_stderr(const char* aFmt, va_list aArgs);
+void vprintf_stderr(const char* aFmt, va_list aArgs) MOZ_FORMAT_PRINTF(1, 0);
 
 /**
  * fprintf_stderr is like fprintf, except that if its file argument
  * is stderr, it invokes printf_stderr instead.
  *
  * This is useful for general debugging code that logs information to a
  * file, but that you would like to be useful on Android and Firefox OS.
  * If you use fprintf_stderr instead of fprintf in such debugging code,
--- a/xpcom/string/nsTSubstring.h
+++ b/xpcom/string/nsTSubstring.h
@@ -687,17 +687,17 @@ public:
 
   /**
    * Append a formatted string to the current string. Uses the
    * standard printf format codes.  This uses NSPR formatting, which will be
    * locale-aware for floating-point values.  You probably don't want to use
    * this with floating-point values as a result.
    */
   void AppendPrintf(const char* aFormat, ...) MOZ_FORMAT_PRINTF(2, 3);
-  void AppendPrintf(const char* aFormat, va_list aAp);
+  void AppendPrintf(const char* aFormat, va_list aAp) MOZ_FORMAT_PRINTF(2, 0);
   void AppendInt(int32_t aInteger)
   {
     AppendPrintf("%" PRId32, aInteger);
   }
   void AppendInt(int32_t aInteger, int aRadix)
   {
     if (aRadix == 10) {
       AppendPrintf("%" PRId32, aInteger);