Bläddra i källkod

Added printf format checking macros. Changed mg_printf() to allocate the buffer on heap if it does not fit the local one.

Sergey Lyubka 13 år sedan
förälder
incheckning
3d3359910f
2 ändrade filer med 47 tillägg och 9 borttagningar
  1. 26 3
      mongoose.c
  2. 21 6
      mongoose.h

+ 26 - 3
mongoose.c

@@ -1467,15 +1467,38 @@ int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
 }
 
 int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
-  char buf[MG_BUF_LEN];
+  char mem[MG_BUF_LEN], *buf = mem;
   int len;
   va_list ap;
 
+  // Print in a local buffer first, hoping that it is large enough to
+  // hold the whole message
   va_start(ap, fmt);
-  len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap);
+  len = vsnprintf(mem, sizeof(mem), fmt, ap);
   va_end(ap);
 
-  return mg_write(conn, buf, (size_t)len);
+  if (len <= 0) {
+    // vsnprintf() error, give up
+    len = -1;
+    cry(conn, "%s(%s, ...): vsnprintf() error", __func__, fmt);
+  } else if (len > (int) sizeof(mem) && (buf = malloc(len + 1)) != NULL) {
+    // Local buffer is not large enough, allocate big buffer on heap
+    va_start(ap, fmt);
+    vsnprintf(buf, len + 1, fmt, ap);
+    va_end(ap);
+    len = mg_write(conn, buf, (size_t) len);
+    free(buf);
+  } else if (len > (int) sizeof(mem)) {
+    // Failed to allocate large enough buffer, give up
+    cry(conn, "%s(%s, ...): Can't allocate %d bytes, not printing anything",
+        __func__, fmt, len);
+    len = -1;
+  } else {
+    // Copy to the local buffer succeeded
+    len = mg_write(conn, buf, (size_t) len);
+  }
+
+  return len;
 }
 
 // URL-decode input buffer into destination buffer.

+ 21 - 6
mongoose.h

@@ -163,14 +163,29 @@ int mg_write(struct mg_connection *, const void *buf, size_t len);
 // Send data to the browser using printf() semantics.
 //
 // Works exactly like mg_write(), but allows to do message formatting.
-// Note that mg_printf() uses internal buffer of size IO_BUF_SIZE
-// (8 Kb by default) as temporary message storage for formatting. Do not
-// print data that is bigger than that, otherwise it will be truncated.
-int mg_printf(struct mg_connection *, const char *fmt, ...)
+// Below are the macros for enabling compiler-specific checks for
+// printf-like arguments.
+
+#undef PRINTF_FORMAT_STRING
+#if _MSC_VER >= 1400
+#include <sal.h>
+#if _MSC_VER > 1400
+#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
+#else
+#define PRINTF_FORMAT_STRING(s) __format_string s
+#endif
+#else
+#define PRINTF_FORMAT_STRING(s) s
+#endif
+
 #ifdef __GNUC__
-__attribute__((format(printf, 2, 3)))
+#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
+#else
+#define PRINTF_ARGS(x, y)
 #endif
-;
+
+int mg_printf(struct mg_connection *,
+              PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
 
 
 // Send contents of the entire file together with HTTP headers.