Commit 3d335991 authored by Sergey Lyubka's avatar Sergey Lyubka

Added printf format checking macros. Changed mg_printf() to allocate the...

Added printf format checking macros. Changed mg_printf() to allocate the buffer on heap if it does not fit the local one.
parent ee8111e4
...@@ -1467,15 +1467,38 @@ int mg_write(struct mg_connection *conn, const void *buf, size_t len) { ...@@ -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, ...) { int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
char buf[MG_BUF_LEN]; char mem[MG_BUF_LEN], *buf = mem;
int len; int len;
va_list ap; va_list ap;
// Print in a local buffer first, hoping that it is large enough to
// hold the whole message
va_start(ap, fmt); va_start(ap, fmt);
len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap); len = vsnprintf(mem, sizeof(mem), fmt, ap);
va_end(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. // URL-decode input buffer into destination buffer.
......
...@@ -163,14 +163,29 @@ int mg_write(struct mg_connection *, const void *buf, size_t len); ...@@ -163,14 +163,29 @@ int mg_write(struct mg_connection *, const void *buf, size_t len);
// Send data to the browser using printf() semantics. // Send data to the browser using printf() semantics.
// //
// Works exactly like mg_write(), but allows to do message formatting. // Works exactly like mg_write(), but allows to do message formatting.
// Note that mg_printf() uses internal buffer of size IO_BUF_SIZE // Below are the macros for enabling compiler-specific checks for
// (8 Kb by default) as temporary message storage for formatting. Do not // printf-like arguments.
// print data that is bigger than that, otherwise it will be truncated.
int mg_printf(struct mg_connection *, const char *fmt, ...) #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__ #ifdef __GNUC__
__attribute__((format(printf, 2, 3))) #define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
#else
#define PRINTF_ARGS(x, y)
#endif #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. // Send contents of the entire file together with HTTP headers.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment