Windows: Provide C99 compliant implementations of (v)snprintf()
authorChris Dickens <christopher.a.dickens@gmail.com>
Thu, 12 Jan 2017 21:55:55 +0000 (13:55 -0800)
committerChris Dickens <christopher.a.dickens@gmail.com>
Thu, 12 Jan 2017 23:26:21 +0000 (15:26 -0800)
The Microsoft implementations of _snprintf() and vsnprintf() do not
guarantee that the output buffer is NULL-terminated, and they do not
return the number of bytes that *would* have been written if truncation
were to occur. This commit adds implementations that do just that.

Note that VS2015 and above provide C99 compliant versions of these
functions, so those will be used when available.

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
libusb/core.c
libusb/libusbi.h
libusb/version_nano.h

index 05de453..be32117 100644 (file)
@@ -2262,6 +2262,47 @@ int API_EXPORTED libusb_has_capability(uint32_t capability)
        return 0;
 }
 
+/* this is defined in libusbi.h if needed */
+#ifdef LIBUSB_PRINTF_WIN32
+/*
+ * Prior to VS2015, Microsoft did not provide the snprintf() function and
+ * provided a vsnprintf() that did not guarantee NULL-terminated output.
+ * Microsoft did provide a _snprintf() function, but again it did not
+ * guarantee NULL-terminated output.
+ *
+ * The below implementations guarantee NULL-terminated output and are
+ * C99 compliant.
+ */
+
+int usbi_snprintf(char *str, size_t size, const char *format, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, format);
+       ret = usbi_vsnprintf(str, size, format, ap);
+       va_end(ap);
+
+       return ret;
+}
+
+int usbi_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+       int ret;
+
+       ret = _vsnprintf(str, size, format, ap);
+       if (ret < 0 || ret == (int)size) {
+               /* Output is truncated, ensure buffer is NULL-terminated and
+                * determine how many characters would have been written. */
+               str[size - 1] = '\0';
+               if (ret < 0)
+                       ret = _vsnprintf(NULL, 0, format, ap);
+       }
+
+       return ret;
+}
+#endif
+
 static void usbi_log_str(struct libusb_context *ctx,
        enum libusb_log_level level, const char * str)
 {
index 9fd634f..752e398 100644 (file)
@@ -540,9 +540,12 @@ int usbi_clear_event(struct libusb_context *ctx);
 #include "os/poll_windows.h"
 #endif
 
-#if (defined(OS_WINDOWS) || defined(OS_WINCE)) && !defined(__GNUC__)
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define snprintf usbi_snprintf
+#define vsnprintf usbi_vsnprintf
+int usbi_snprintf(char *dst, size_t size, const char *format, ...);
+int usbi_vsnprintf(char *dst, size_t size, const char *format, va_list ap);
+#define LIBUSB_PRINTF_WIN32
 #endif
 
 struct usbi_pollfd {
index 963fb81..1784094 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 11172
+#define LIBUSB_NANO 11173