Merge branch 'snprintf' into development

* snprintf:
  Rationalize other snprintf() uses
  Rationalize snprintf() usage in X.509 modules
  Add tests for snprintf
  Include fixed snprintf for Windows in platform.c
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 9fb870a..2445031 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -39,6 +39,10 @@
 #error "mbed TLS requires a platform with 8-bit chars"
 #endif
 
+#if defined(_WIN32) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_C is required on Windows"
+#endif
+
 #if defined(MBEDTLS_DEPRECATED_WARNING) && \
     !defined(__GNUC__) && !defined(__clang__)
 #error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang"
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 1fe730c..33b20c0 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -142,10 +142,7 @@
  *
  * All these define require MBEDTLS_PLATFORM_C to be defined!
  *
- * WARNING: MBEDTLS_PLATFORM_SNPRINTF_ALT is not available on Windows
- * for compatibility reasons.
- *
- * WARNING: MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as
+ * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as
  * MBEDTLS_PLATFORM_XXX_MACRO!
  *
  * Uncomment a macro to enable alternate implementation of specific base
@@ -2004,12 +2001,15 @@
  * \def MBEDTLS_PLATFORM_C
  *
  * Enable the platform abstraction layer that allows you to re-assign
- * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit()
+ * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit().
  *
  * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT
  * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned
  * above to be specified at runtime or compile time respectively.
  *
+ * \note This abstraction layer must be enabled on Windows (including MSYS2)
+ * as other module rely on it for a fixed snprintf implementation.
+ *
  * Module:  library/platform.c
  * Caller:  Most other .c files
  *
@@ -2379,6 +2379,7 @@
 //#define MBEDTLS_PLATFORM_STD_EXIT            exit /**< Default exit to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_FPRINTF      fprintf /**< Default fprintf to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_PRINTF        printf /**< Default printf to use, can be undefined */
+/* Note: your snprintf must correclty zero-terminate the buffer! */
 //#define MBEDTLS_PLATFORM_STD_SNPRINTF    snprintf /**< Default snprintf to use, can be undefined */
 
 /* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */
@@ -2388,6 +2389,7 @@
 //#define MBEDTLS_PLATFORM_EXIT_MACRO            exit /**< Default exit macro to use, can be undefined */
 //#define MBEDTLS_PLATFORM_FPRINTF_MACRO      fprintf /**< Default fprintf macro to use, can be undefined */
 //#define MBEDTLS_PLATFORM_PRINTF_MACRO        printf /**< Default printf macro to use, can be undefined */
+/* Note: your snprintf must correclty zero-terminate the buffer! */
 //#define MBEDTLS_PLATFORM_SNPRINTF_MACRO    snprintf /**< Default snprintf macro to use, can be undefined */
 
 /* SSL Cache options */
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index 4f43018..cb5a697 100644
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -72,7 +72,7 @@
  * Name      ID  Nr of Errors
  * PEM       1   9
  * PKCS#12   1   4 (Started from top)
- * X509      2   18
+ * X509      2   19
  * PKCS5     2   4 (Started from top)
  * DHM       3   9
  * PK        3   14 (Started from top)
diff --git a/include/mbedtls/platform.h b/include/mbedtls/platform.h
index b71a09c..5dab974 100644
--- a/include/mbedtls/platform.h
+++ b/include/mbedtls/platform.h
@@ -46,8 +46,12 @@
 #include <stdio.h>
 #include <stdlib.h>
 #if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
+#if defined(_WIN32)
+#define MBEDTLS_PLATFORM_STD_SNPRINTF   mbedtls_platform_win32_snprintf /**< Default snprintf to use  */
+#else
 #define MBEDTLS_PLATFORM_STD_SNPRINTF   snprintf /**< Default snprintf to use  */
 #endif
+#endif
 #if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
 #define MBEDTLS_PLATFORM_STD_PRINTF   printf /**< Default printf to use  */
 #endif
@@ -150,7 +154,18 @@
 
 /*
  * The function pointers for snprintf
+ *
+ * The snprintf implementation should conform to C99:
+ * - it *must* always correctly zero-terminate the buffer
+ *   (except when n == 0, then it must leave the buffer untouched)
+ * - however it is acceptable to return -1 instead of the required length when
+ *   the destination buffer is too short.
  */
+#if defined(_WIN32)
+/* For Windows (inc. MSYS2), we provide our own fixed implementation */
+int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... );
+#endif
+
 #if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
 extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... );
 
diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h
index 2afe4fa..59986d8 100644
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -76,6 +76,7 @@
 #define MBEDTLS_ERR_X509_BAD_INPUT_DATA                   -0x2800  /**< Input invalid. */
 #define MBEDTLS_ERR_X509_ALLOC_FAILED                     -0x2880  /**< Allocation of memory failed. */
 #define MBEDTLS_ERR_X509_FILE_IO_ERROR                    -0x2900  /**< Read/write of file failed. */
+#define MBEDTLS_ERR_X509_BUFFER_TOO_SMALL                 -0x2980  /**< Destination buffer is too small. */
 /* \} name */
 
 /**
@@ -306,6 +307,15 @@
                     const char *oid, size_t oid_len,
                     unsigned char *sig, size_t size );
 
+#define MBEDTLS_X509_SAFE_SNPRINTF                          \
+    do {                                                    \
+        if( ret < 0 || (size_t) ret >= n )                  \
+            return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );    \
+                                                            \
+        n -= (size_t) ret;                                  \
+        p += (size_t) ret;                                  \
+    } while( 0 )
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/library/debug.c b/library/debug.c
index c71f4df..0aeb0e4 100644
--- a/library/debug.c
+++ b/library/debug.c
@@ -34,16 +34,6 @@
 #include <stdio.h>
 #include <string.h>
 
-#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
-#if !defined  snprintf
-#define  snprintf  _snprintf
-#endif
-
-#if !defined vsnprintf
-#define vsnprintf _vsnprintf
-#endif
-#endif /* _MSC_VER */
-
 #if defined(MBEDTLS_PLATFORM_C)
 #include "mbedtls/platform.h"
 #else
@@ -67,13 +57,15 @@
 {
     va_list argp;
     static char str[512];
-    int maxlen = sizeof( str ) - 1;
 
     va_start( argp, format );
-    vsnprintf( str, maxlen, format, argp );
+#if defined(_WIN32)
+    _vsnprintf_s( str, sizeof( str ), _TRUNCATE, format, argp );
+#else
+    vsnprintf( str, sizeof( str ), format, argp );
+#endif
     va_end( argp );
 
-    str[maxlen] = '\0';
     return( str );
 }
 
@@ -81,7 +73,6 @@
                       const char *file, int line, const char *text )
 {
     char str[512];
-    int maxlen = sizeof( str ) - 1;
 
     if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
         return;
@@ -92,8 +83,7 @@
         return;
     }
 
-    mbedtls_snprintf( str, maxlen, "%s(%04d): %s\n", file, line, text );
-    str[maxlen] = '\0';
+    mbedtls_snprintf( str, sizeof( str ), "%s(%04d): %s\n", file, line, text );
     ssl->conf->f_dbg( ssl->conf->p_dbg, level, str );
 }
 
@@ -102,7 +92,6 @@
                       const char *text, int ret )
 {
     char str[512];
-    int maxlen = sizeof( str ) - 1;
     size_t idx = 0;
 
     if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
@@ -117,12 +106,11 @@
         return;
 
     if( debug_log_mode == MBEDTLS_DEBUG_LOG_FULL )
-        idx = mbedtls_snprintf( str, maxlen, "%s(%04d): ", file, line );
+        idx = mbedtls_snprintf( str, sizeof( str ), "%s(%04d): ", file, line );
 
-    mbedtls_snprintf( str + idx, maxlen - idx, "%s() returned %d (-0x%04x)\n",
+    mbedtls_snprintf( str + idx, sizeof( str ) - idx, "%s() returned %d (-0x%04x)\n",
               text, ret, -ret );
 
-    str[maxlen] = '\0';
     ssl->conf->f_dbg( ssl->conf->p_dbg, level, str );
 }
 
@@ -132,18 +120,17 @@
 {
     char str[512];
     char txt[17];
-    size_t i, maxlen = sizeof( str ) - 1, idx = 0;
+    size_t i, idx = 0;
 
     if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
         return;
 
     if( debug_log_mode == MBEDTLS_DEBUG_LOG_FULL )
-        idx = mbedtls_snprintf( str, maxlen, "%s(%04d): ", file, line );
+        idx = mbedtls_snprintf( str, sizeof( str ), "%s(%04d): ", file, line );
 
-    mbedtls_snprintf( str + idx, maxlen - idx, "dumping '%s' (%u bytes)\n",
+    mbedtls_snprintf( str + idx, sizeof( str ) - idx, "dumping '%s' (%u bytes)\n",
               text, (unsigned int) len );
 
-    str[maxlen] = '\0';
     ssl->conf->f_dbg( ssl->conf->p_dbg, level, str );
 
     idx = 0;
@@ -157,7 +144,7 @@
         {
             if( i > 0 )
             {
-                mbedtls_snprintf( str + idx, maxlen - idx, "  %s\n", txt );
+                mbedtls_snprintf( str + idx, sizeof( str ) - idx, "  %s\n", txt );
                 ssl->conf->f_dbg( ssl->conf->p_dbg, level, str );
 
                 idx = 0;
@@ -165,14 +152,14 @@
             }
 
             if( debug_log_mode == MBEDTLS_DEBUG_LOG_FULL )
-                idx = mbedtls_snprintf( str, maxlen, "%s(%04d): ", file, line );
+                idx = mbedtls_snprintf( str, sizeof( str ), "%s(%04d): ", file, line );
 
-            idx += mbedtls_snprintf( str + idx, maxlen - idx, "%04x: ",
+            idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, "%04x: ",
                              (unsigned int) i );
 
         }
 
-        idx += mbedtls_snprintf( str + idx, maxlen - idx, " %02x",
+        idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %02x",
                          (unsigned int) buf[i] );
         txt[i % 16] = ( buf[i] > 31 && buf[i] < 127 ) ? buf[i] : '.' ;
     }
@@ -180,9 +167,9 @@
     if( len > 0 )
     {
         for( /* i = i */; i % 16 != 0; i++ )
-            idx += mbedtls_snprintf( str + idx, maxlen - idx, "   " );
+            idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, "   " );
 
-        mbedtls_snprintf( str + idx, maxlen - idx, "  %s\n", txt );
+        mbedtls_snprintf( str + idx, sizeof( str ) - idx, "  %s\n", txt );
         ssl->conf->f_dbg( ssl->conf->p_dbg, level, str );
     }
 }
@@ -193,17 +180,14 @@
                       const char *text, const mbedtls_ecp_point *X )
 {
     char str[512];
-    int maxlen = sizeof( str ) - 1;
 
     if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
         return;
 
-    mbedtls_snprintf( str, maxlen, "%s(X)", text );
-    str[maxlen] = '\0';
+    mbedtls_snprintf( str, sizeof( str ), "%s(X)", text );
     mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->X );
 
-    mbedtls_snprintf( str, maxlen, "%s(Y)", text );
-    str[maxlen] = '\0';
+    mbedtls_snprintf( str, sizeof( str ), "%s(Y)", text );
     mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->Y );
 }
 #endif /* MBEDTLS_ECP_C */
@@ -214,7 +198,7 @@
                       const char *text, const mbedtls_mpi *X )
 {
     char str[512];
-    int j, k, maxlen = sizeof( str ) - 1, zeros = 1;
+    int j, k, zeros = 1;
     size_t i, n, idx = 0;
 
     if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || X == NULL || level > debug_threshold )
@@ -229,12 +213,11 @@
             break;
 
     if( debug_log_mode == MBEDTLS_DEBUG_LOG_FULL )
-        idx = mbedtls_snprintf( str, maxlen, "%s(%04d): ", file, line );
+        idx = mbedtls_snprintf( str, sizeof( str ), "%s(%04d): ", file, line );
 
-    mbedtls_snprintf( str + idx, maxlen - idx, "value of '%s' (%d bits) is:\n",
+    mbedtls_snprintf( str + idx, sizeof( str ) - idx, "value of '%s' (%d bits) is:\n",
               text, (int) ( ( n * ( sizeof(mbedtls_mpi_uint) << 3 ) ) + j + 1 ) );
 
-    str[maxlen] = '\0';
     ssl->conf->f_dbg( ssl->conf->p_dbg, level, str );
 
     idx = 0;
@@ -254,16 +237,16 @@
             {
                 if( j > 0 )
                 {
-                    mbedtls_snprintf( str + idx, maxlen - idx, "\n" );
+                    mbedtls_snprintf( str + idx, sizeof( str ) - idx, "\n" );
                     ssl->conf->f_dbg( ssl->conf->p_dbg, level, str );
                     idx = 0;
                 }
 
                 if( debug_log_mode == MBEDTLS_DEBUG_LOG_FULL )
-                    idx = mbedtls_snprintf( str, maxlen, "%s(%04d): ", file, line );
+                    idx = mbedtls_snprintf( str, sizeof( str ), "%s(%04d): ", file, line );
             }
 
-            idx += mbedtls_snprintf( str + idx, maxlen - idx, " %02x", (unsigned int)
+            idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %02x", (unsigned int)
                              ( X->p[i - 1] >> ( k << 3 ) ) & 0xFF );
 
             j++;
@@ -275,13 +258,13 @@
     {
         if( debug_log_mode == MBEDTLS_DEBUG_LOG_FULL )
         {
-            idx = mbedtls_snprintf( str, maxlen, "%s(%04d): ", file, line );
+            idx = mbedtls_snprintf( str, sizeof( str ), "%s(%04d): ", file, line );
 
         }
-        idx += mbedtls_snprintf( str + idx, maxlen - idx, " 00" );
+        idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " 00" );
     }
 
-    mbedtls_snprintf( str + idx, maxlen - idx, "\n" );
+    mbedtls_snprintf( str + idx, sizeof( str ) - idx, "\n" );
     ssl->conf->f_dbg( ssl->conf->p_dbg, level, str );
 }
 #endif /* MBEDTLS_BIGNUM_C */
@@ -328,33 +311,29 @@
                       const char *text, const mbedtls_x509_crt *crt )
 {
     char str[1024], prefix[64];
-    int i = 0, maxlen = sizeof( prefix ) - 1, idx = 0;
+    int i = 0, idx = 0;
 
     if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || crt == NULL || level > debug_threshold )
         return;
 
     if( debug_log_mode == MBEDTLS_DEBUG_LOG_FULL )
     {
-        mbedtls_snprintf( prefix, maxlen, "%s(%04d): ", file, line );
-        prefix[maxlen] = '\0';
+        mbedtls_snprintf( prefix, sizeof( prefix ), "%s(%04d): ", file, line );
     }
     else
         prefix[0] = '\0';
 
-    maxlen = sizeof( str ) - 1;
-
     while( crt != NULL )
     {
         char buf[1024];
         mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, prefix, crt );
 
         if( debug_log_mode == MBEDTLS_DEBUG_LOG_FULL )
-            idx = mbedtls_snprintf( str, maxlen, "%s(%04d): ", file, line );
+            idx = mbedtls_snprintf( str, sizeof( str ), "%s(%04d): ", file, line );
 
-        mbedtls_snprintf( str + idx, maxlen - idx, "%s #%d:\n%s",
+        mbedtls_snprintf( str + idx, sizeof( str ) - idx, "%s #%d:\n%s",
                   text, ++i, buf );
 
-        str[maxlen] = '\0';
         ssl->conf->f_dbg( ssl->conf->p_dbg, level, str );
 
         debug_print_pk( ssl, level, file, line, "crt->", &crt->pk );
diff --git a/library/error.c b/library/error.c
index f0a86f6..21be423 100644
--- a/library/error.c
+++ b/library/error.c
@@ -149,10 +149,6 @@
 #include "mbedtls/xtea.h"
 #endif
 
-#if defined(_MSC_VER) && !defined  snprintf && !defined(EFIX64) && \
-    !defined(EFI32)
-#define  snprintf  _snprintf
-#endif
 
 void mbedtls_strerror( int ret, char *buf, size_t buflen )
 {
@@ -163,8 +159,6 @@
         return;
 
     memset( buf, 0x00, buflen );
-    /* Reduce buflen to make sure MSVC _snprintf() ends with \0 as well */
-    buflen -= 1;
 
     if( ret < 0 )
         ret = -ret;
@@ -474,6 +468,8 @@
             mbedtls_snprintf( buf, buflen, "X509 - Allocation of memory failed" );
         if( use_ret == -(MBEDTLS_ERR_X509_FILE_IO_ERROR) )
             mbedtls_snprintf( buf, buflen, "X509 - Read/write of file failed" );
+        if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) )
+            mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" );
 #endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */
         // END generated code
 
diff --git a/library/net.c b/library/net.c
index 8eb5172..e6dd5db 100644
--- a/library/net.c
+++ b/library/net.c
@@ -77,11 +77,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 
-#if defined(_MSC_VER) && !defined  snprintf && !defined(EFIX64) && \
-    !defined(EFI32)
-#define  snprintf  _snprintf
-#endif
-
 #include <time.h>
 
 #if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
diff --git a/library/oid.c b/library/oid.c
index 0913552..f14282a 100644
--- a/library/oid.c
+++ b/library/oid.c
@@ -598,55 +598,14 @@
 FN_OID_GET_ATTR2(mbedtls_oid_get_pkcs12_pbe_alg, oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, mbedtls_md_type_t, md_alg, mbedtls_cipher_type_t, cipher_alg)
 #endif /* MBEDTLS_PKCS12_C */
 
-#if defined(_MSC_VER) && !defined snprintf && !defined(EFIX64) && \
-    !defined(EFI32)
-#include <stdarg.h>
-
-#if !defined vsnprintf
-#define vsnprintf _vsnprintf
-#endif // vsnprintf
-
-/*
- * Windows _snprintf and _vsnprintf are not compatible to linux versions.
- * Result value is not size of buffer needed, but -1 if no fit is possible.
- *
- * This fuction tries to 'fix' this by at least suggesting enlarging the
- * size by 20.
- */
-static int compat_snprintf( char *str, size_t size, const char *format, ... )
-{
-    va_list ap;
-    int res = -1;
-
-    va_start( ap, format );
-
-    res = vsnprintf( str, size, format, ap );
-
-    va_end( ap );
-
-    // No quick fix possible
-    if( res < 0 )
-        return( (int) size + 20 );
-
-    return( res );
-}
-
-#define snprintf compat_snprintf
-#endif /* _MSC_VER && !snprintf && !EFIX64 && !EFI32 */
-
-#define SAFE_SNPRINTF()                             \
-{                                                   \
-    if( ret == -1 )                                 \
-        return( MBEDTLS_ERR_OID_BUF_TOO_SMALL );   \
-                                                    \
-    if( (unsigned int) ret >= n ) {                 \
-        p[n - 1] = '\0';                            \
-        return( MBEDTLS_ERR_OID_BUF_TOO_SMALL );   \
-    }                                               \
-                                                    \
-    n -= (unsigned int) ret;                        \
-    p += (unsigned int) ret;                        \
-}
+#define OID_SAFE_SNPRINTF                               \
+    do {                                                \
+        if( ret < 0 || (size_t) ret >= n )              \
+            return( MBEDTLS_ERR_OID_BUF_TOO_SMALL );    \
+                                                        \
+        n -= (size_t) ret;                              \
+        p += (size_t) ret;                              \
+    } while( 0 )
 
 /* Return the x.y.z.... style numeric string for the given OID */
 int mbedtls_oid_get_numeric_string( char *buf, size_t size,
@@ -664,7 +623,7 @@
     if( oid->len > 0 )
     {
         ret = mbedtls_snprintf( p, n, "%d.%d", oid->p[0] / 40, oid->p[0] % 40 );
-        SAFE_SNPRINTF();
+        OID_SAFE_SNPRINTF;
     }
 
     value = 0;
@@ -681,7 +640,7 @@
         {
             /* Last byte */
             ret = mbedtls_snprintf( p, n, ".%d", value );
-            SAFE_SNPRINTF();
+            OID_SAFE_SNPRINTF;
             value = 0;
         }
     }
diff --git a/library/platform.c b/library/platform.c
index 123267a..23dba94 100644
--- a/library/platform.c
+++ b/library/platform.c
@@ -63,6 +63,21 @@
 }
 #endif /* MBEDTLS_PLATFORM_MEMORY */
 
+#if defined(_WIN32)
+#include <stdarg.h>
+int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... )
+{
+    int ret;
+    va_list argp;
+
+    va_start( argp, fmt );
+    ret = _vsnprintf_s( s, n, _TRUNCATE, fmt, argp );
+    va_end( argp );
+
+    return( ret );
+}
+#endif
+
 #if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
 #if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
 /*
diff --git a/library/x509.c b/library/x509.c
index 0ca4b4a..d5f93d0 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -662,58 +662,6 @@
     return( 0 );
 }
 
-#if defined(_MSC_VER) && !defined snprintf && !defined(EFIX64) && \
-    !defined(EFI32)
-#include <stdarg.h>
-
-#if !defined vsnprintf
-#define vsnprintf _vsnprintf
-#endif // vsnprintf
-
-/*
- * Windows _snprintf and _vsnprintf are not compatible to linux versions.
- * Result value is not size of buffer needed, but -1 if no fit is possible.
- *
- * This fuction tries to 'fix' this by at least suggesting enlarging the
- * size by 20.
- */
-static int compat_snprintf( char *str, size_t size, const char *format, ... )
-{
-    va_list ap;
-    int res = -1;
-
-    va_start( ap, format );
-
-    res = vsnprintf( str, size, format, ap );
-
-    va_end( ap );
-
-    // No quick fix possible
-    if( res < 0 )
-        return( (int) size + 20 );
-
-    return( res );
-}
-
-#define snprintf compat_snprintf
-#endif /* _MSC_VER && !snprintf && !EFIX64 && !EFI32 */
-
-#define ERR_BUF_TOO_SMALL    -2
-
-#define SAFE_SNPRINTF()                             \
-{                                                   \
-    if( ret == -1 )                                 \
-        return( -1 );                               \
-                                                    \
-    if( (unsigned int) ret > n ) {                  \
-        p[n - 1] = '\0';                            \
-        return( ERR_BUF_TOO_SMALL ); \
-    }                                               \
-                                                    \
-    n -= (unsigned int) ret;                        \
-    p += (unsigned int) ret;                        \
-}
-
 /*
  * Store the name in printable form into buf; no more
  * than size characters will be written
@@ -744,7 +692,7 @@
         if( name != dn )
         {
             ret = mbedtls_snprintf( p, n, merge ? " + " : ", " );
-            SAFE_SNPRINTF();
+            MBEDTLS_X509_SAFE_SNPRINTF;
         }
 
         ret = mbedtls_oid_get_attr_short_name( &name->oid, &short_name );
@@ -753,7 +701,7 @@
             ret = mbedtls_snprintf( p, n, "%s=", short_name );
         else
             ret = mbedtls_snprintf( p, n, "\?\?=" );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         for( i = 0; i < name->val.len; i++ )
         {
@@ -767,7 +715,7 @@
         }
         s[i] = '\0';
         ret = mbedtls_snprintf( p, n, "%s", s );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         merge = name->next_merged;
         name = name->next;
@@ -799,13 +747,13 @@
 
         ret = mbedtls_snprintf( p, n, "%02X%s",
                 serial->p[i], ( i < nr - 1 ) ? ":" : "" );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
     }
 
     if( nr != serial->len )
     {
         ret = mbedtls_snprintf( p, n, "...." );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
     }
 
     return( (int) ( size - n ) );
@@ -828,7 +776,7 @@
         ret = mbedtls_snprintf( p, n, "???"  );
     else
         ret = mbedtls_snprintf( p, n, "%s", desc );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
 #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
     if( pk_alg == MBEDTLS_PK_RSASSA_PSS )
@@ -845,7 +793,7 @@
                               md_info ? mbedtls_md_get_name( md_info ) : "???",
                               mgf_md_info ? mbedtls_md_get_name( mgf_md_info ) : "???",
                               pss_opts->expected_salt_len );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
     }
 #else
     ((void) pk_alg);
@@ -865,11 +813,8 @@
     size_t n = buf_size;
     int ret;
 
-    if( strlen( name ) + sizeof( " key size" ) > buf_size )
-        return( ERR_BUF_TOO_SMALL );
-
     ret = mbedtls_snprintf( p, n, "%s key size", name );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     return( 0 );
 }
diff --git a/library/x509_crl.c b/library/x509_crl.c
index 61b1bec..85de930 100644
--- a/library/x509_crl.c
+++ b/library/x509_crl.c
@@ -569,58 +569,6 @@
 }
 #endif /* MBEDTLS_FS_IO */
 
-#if defined(_MSC_VER) && !defined snprintf && !defined(EFIX64) && \
-    !defined(EFI32)
-#include <stdarg.h>
-
-#if !defined vsnprintf
-#define vsnprintf _vsnprintf
-#endif // vsnprintf
-
-/*
- * Windows _snprintf and _vsnprintf are not compatible to linux versions.
- * Result value is not size of buffer needed, but -1 if no fit is possible.
- *
- * This fuction tries to 'fix' this by at least suggesting enlarging the
- * size by 20.
- */
-static int compat_snprintf( char *str, size_t size, const char *format, ... )
-{
-    va_list ap;
-    int res = -1;
-
-    va_start( ap, format );
-
-    res = vsnprintf( str, size, format, ap );
-
-    va_end( ap );
-
-    // No quick fix possible
-    if( res < 0 )
-        return( (int) size + 20 );
-
-    return( res );
-}
-
-#define snprintf compat_snprintf
-#endif /* _MSC_VER && !snprintf && !EFIX64 && !EFI32 */
-
-#define ERR_BUF_TOO_SMALL    -2
-
-#define SAFE_SNPRINTF()                             \
-{                                                   \
-    if( ret == -1 )                                 \
-        return( -1 );                               \
-                                                    \
-    if( (unsigned int) ret > n ) {                  \
-        p[n - 1] = '\0';                            \
-        return( ERR_BUF_TOO_SMALL ); \
-    }                                               \
-                                                    \
-    n -= (unsigned int) ret;                        \
-    p += (unsigned int) ret;                        \
-}
-
 /*
  * Return an informational string about the certificate.
  */
@@ -642,61 +590,61 @@
 
     ret = mbedtls_snprintf( p, n, "%sCRL version   : %d",
                                prefix, crl->version );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%sissuer name   : ", prefix );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
     ret = mbedtls_x509_dn_gets( p, n, &crl->issuer );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%sthis update   : " \
                    "%04d-%02d-%02d %02d:%02d:%02d", prefix,
                    crl->this_update.year, crl->this_update.mon,
                    crl->this_update.day,  crl->this_update.hour,
                    crl->this_update.min,  crl->this_update.sec );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%snext update   : " \
                    "%04d-%02d-%02d %02d:%02d:%02d", prefix,
                    crl->next_update.year, crl->next_update.mon,
                    crl->next_update.day,  crl->next_update.hour,
                    crl->next_update.min,  crl->next_update.sec );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     entry = &crl->entry;
 
     ret = mbedtls_snprintf( p, n, "\n%sRevoked certificates:",
                                prefix );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     while( entry != NULL && entry->raw.len != 0 )
     {
         ret = mbedtls_snprintf( p, n, "\n%sserial number: ",
                                prefix );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         ret = mbedtls_x509_serial_gets( p, n, &entry->serial );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         ret = mbedtls_snprintf( p, n, " revocation date: " \
                    "%04d-%02d-%02d %02d:%02d:%02d",
                    entry->revocation_date.year, entry->revocation_date.mon,
                    entry->revocation_date.day,  entry->revocation_date.hour,
                    entry->revocation_date.min,  entry->revocation_date.sec );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         entry = entry->next;
     }
 
     ret = mbedtls_snprintf( p, n, "\n%ssigned using  : ", prefix );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_x509_sig_alg_gets( p, n, &crl->sig_oid, crl->sig_pk, crl->sig_md,
                              crl->sig_opts );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n" );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     return( (int) ( size - n ) );
 }
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 7cb5b44..0c3450a 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1194,58 +1194,6 @@
 }
 #endif /* MBEDTLS_FS_IO */
 
-#if defined(_MSC_VER) && !defined snprintf && !defined(EFIX64) && \
-    !defined(EFI32)
-#include <stdarg.h>
-
-#if !defined vsnprintf
-#define vsnprintf _vsnprintf
-#endif // vsnprintf
-
-/*
- * Windows _snprintf and _vsnprintf are not compatible to linux versions.
- * Result value is not size of buffer needed, but -1 if no fit is possible.
- *
- * This fuction tries to 'fix' this by at least suggesting enlarging the
- * size by 20.
- */
-static int compat_snprintf( char *str, size_t size, const char *format, ... )
-{
-    va_list ap;
-    int res = -1;
-
-    va_start( ap, format );
-
-    res = vsnprintf( str, size, format, ap );
-
-    va_end( ap );
-
-    // No quick fix possible
-    if( res < 0 )
-        return( (int) size + 20 );
-
-    return( res );
-}
-
-#define snprintf compat_snprintf
-#endif /* _MSC_VER  && !snprintf && !EFIX64 && !EFI32 */
-
-#define ERR_BUF_TOO_SMALL    -2
-
-#define SAFE_SNPRINTF()                             \
-{                                                   \
-    if( ret == -1 )                                 \
-        return( -1 );                               \
-                                                    \
-    if( (unsigned int) ret > n ) {                  \
-        p[n - 1] = '\0';                            \
-        return( ERR_BUF_TOO_SMALL ); \
-    }                                               \
-                                                    \
-    n -= (unsigned int) ret;                        \
-    p += (unsigned int) ret;                        \
-}
-
 static int x509_info_subject_alt_name( char **buf, size_t *size,
                                        const mbedtls_x509_sequence *subject_alt_name )
 {
@@ -1261,7 +1209,7 @@
         if( cur->buf.len + sep_len >= n )
         {
             *p = '\0';
-            return( ERR_BUF_TOO_SMALL );
+            return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
         }
 
         n -= cur->buf.len + sep_len;
@@ -1287,7 +1235,7 @@
 #define PRINT_ITEM(i)                           \
     {                                           \
         ret = mbedtls_snprintf( p, n, "%s" i, sep );    \
-        SAFE_SNPRINTF();                        \
+        MBEDTLS_X509_SAFE_SNPRINTF;                        \
         sep = ", ";                             \
     }
 
@@ -1360,7 +1308,7 @@
             desc = "???";
 
         ret = mbedtls_snprintf( p, n, "%s%s", sep, desc );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         sep = ", ";
 
@@ -1391,44 +1339,44 @@
 
     ret = mbedtls_snprintf( p, n, "%scert. version     : %d\n",
                                prefix, crt->version );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
     ret = mbedtls_snprintf( p, n, "%sserial number     : ",
                                prefix );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_x509_serial_gets( p, n, &crt->serial );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%sissuer name       : ", prefix );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
     ret = mbedtls_x509_dn_gets( p, n, &crt->issuer  );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%ssubject name      : ", prefix );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
     ret = mbedtls_x509_dn_gets( p, n, &crt->subject );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%sissued  on        : " \
                    "%04d-%02d-%02d %02d:%02d:%02d", prefix,
                    crt->valid_from.year, crt->valid_from.mon,
                    crt->valid_from.day,  crt->valid_from.hour,
                    crt->valid_from.min,  crt->valid_from.sec );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%sexpires on        : " \
                    "%04d-%02d-%02d %02d:%02d:%02d", prefix,
                    crt->valid_to.year, crt->valid_to.mon,
                    crt->valid_to.day,  crt->valid_to.hour,
                    crt->valid_to.min,  crt->valid_to.sec );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%ssigned using      : ", prefix );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk,
                              crt->sig_md, crt->sig_opts );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     /* Key size */
     if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON,
@@ -1439,7 +1387,7 @@
 
     ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str,
                           (int) mbedtls_pk_get_bitlen( &crt->pk ) );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     /*
      * Optional extensions
@@ -1449,19 +1397,19 @@
     {
         ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix,
                         crt->ca_istrue ? "true" : "false" );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         if( crt->max_pathlen > 0 )
         {
             ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 );
-            SAFE_SNPRINTF();
+            MBEDTLS_X509_SAFE_SNPRINTF;
         }
     }
 
     if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
     {
         ret = mbedtls_snprintf( p, n, "\n%ssubject alt name  : ", prefix );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         if( ( ret = x509_info_subject_alt_name( &p, &n,
                                             &crt->subject_alt_names ) ) != 0 )
@@ -1471,7 +1419,7 @@
     if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE )
     {
         ret = mbedtls_snprintf( p, n, "\n%scert. type        : ", prefix );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 )
             return( ret );
@@ -1480,7 +1428,7 @@
     if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE )
     {
         ret = mbedtls_snprintf( p, n, "\n%skey usage         : ", prefix );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 )
             return( ret );
@@ -1489,7 +1437,7 @@
     if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE )
     {
         ret = mbedtls_snprintf( p, n, "\n%sext key usage     : ", prefix );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
 
         if( ( ret = x509_info_ext_key_usage( &p, &n,
                                              &crt->ext_key_usage ) ) != 0 )
@@ -1497,7 +1445,7 @@
     }
 
     ret = mbedtls_snprintf( p, n, "\n" );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     return( (int) ( size - n ) );
 }
@@ -1545,7 +1493,7 @@
             continue;
 
         ret = mbedtls_snprintf( p, n, "%s%s\n", prefix, cur->string );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
         flags ^= cur->code;
     }
 
@@ -1553,7 +1501,7 @@
     {
         ret = mbedtls_snprintf( p, n, "%sUnknown reason "
                                        "(this should not happen)\n", prefix );
-        SAFE_SNPRINTF();
+        MBEDTLS_X509_SAFE_SNPRINTF;
     }
 
     return( (int) ( size - n ) );
diff --git a/library/x509_csr.c b/library/x509_csr.c
index 18ace67..0e727b4 100644
--- a/library/x509_csr.c
+++ b/library/x509_csr.c
@@ -327,58 +327,6 @@
 }
 #endif /* MBEDTLS_FS_IO */
 
-#if defined(_MSC_VER) && !defined snprintf && !defined(EFIX64) && \
-    !defined(EFI32)
-#include <stdarg.h>
-
-#if !defined vsnprintf
-#define vsnprintf _vsnprintf
-#endif // vsnprintf
-
-/*
- * Windows _snprintf and _vsnprintf are not compatible to linux versions.
- * Result value is not size of buffer needed, but -1 if no fit is possible.
- *
- * This fuction tries to 'fix' this by at least suggesting enlarging the
- * size by 20.
- */
-static int compat_snprintf( char *str, size_t size, const char *format, ... )
-{
-    va_list ap;
-    int res = -1;
-
-    va_start( ap, format );
-
-    res = vsnprintf( str, size, format, ap );
-
-    va_end( ap );
-
-    // No quick fix possible
-    if( res < 0 )
-        return( (int) size + 20 );
-
-    return( res );
-}
-
-#define snprintf compat_snprintf
-#endif /* _MSC_VER && !snprintf && !EFIX64 && !EFI32 */
-
-#define ERR_BUF_TOO_SMALL    -2
-
-#define SAFE_SNPRINTF()                             \
-{                                                   \
-    if( ret == -1 )                                 \
-        return( -1 );                               \
-                                                    \
-    if( (unsigned int) ret > n ) {                  \
-        p[n - 1] = '\0';                            \
-        return( ERR_BUF_TOO_SMALL ); \
-    }                                               \
-                                                    \
-    n -= (unsigned int) ret;                        \
-    p += (unsigned int) ret;                        \
-}
-
 #define BEFORE_COLON    14
 #define BC              "14"
 /*
@@ -397,19 +345,19 @@
 
     ret = mbedtls_snprintf( p, n, "%sCSR version   : %d",
                                prefix, csr->version );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%ssubject name  : ", prefix );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
     ret = mbedtls_x509_dn_gets( p, n, &csr->subject );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_snprintf( p, n, "\n%ssigned using  : ", prefix );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     ret = mbedtls_x509_sig_alg_gets( p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md,
                              csr->sig_opts );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON,
                                       mbedtls_pk_get_name( &csr->pk ) ) ) != 0 )
@@ -419,7 +367,7 @@
 
     ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str,
                           (int) mbedtls_pk_get_bitlen( &csr->pk ) );
-    SAFE_SNPRINTF();
+    MBEDTLS_X509_SAFE_SNPRINTF;
 
     return( (int) ( size - n ) );
 }
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
index 5c1d354..c46b8e7 100644
--- a/programs/test/selftest.c
+++ b/programs/test/selftest.c
@@ -60,12 +60,41 @@
 #else
 #include <stdio.h>
 #define mbedtls_printf     printf
+#define mbedtls_snprintf   snprintf
 #endif
 
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
 #include "mbedtls/memory_buffer_alloc.h"
 #endif
 
+static int test_snprintf( size_t n, const char ref_buf[10], int ref_ret )
+{
+    int ret;
+    char buf[10] = "xxxxxxxxx";
+
+    ret = mbedtls_snprintf( buf, n, "%s", "123" );
+    if( ret < 0 || (size_t) ret >= n )
+        ret = -1;
+
+    if( memcmp( ref_buf, buf, sizeof buf ) != 0 ||
+        ref_ret != ret )
+    {
+        return( 1 );
+    }
+
+    return( 0 );
+}
+
+static int run_test_snprintf( void )
+{
+    return( test_snprintf( 0, "xxxxxxxxx",  -1 ) != 0 ||
+            test_snprintf( 1, "\0xxxxxxxx", -1 ) != 0 ||
+            test_snprintf( 2, "1\0xxxxxxx", -1 ) != 0 ||
+            test_snprintf( 3, "12\0xxxxxx", -1 ) != 0 ||
+            test_snprintf( 4, "123\0xxxxx",  3 ) != 0 ||
+            test_snprintf( 5, "123\0xxxxx",  3 ) != 0 );
+}
+
 int main( int argc, char *argv[] )
 {
     int ret = 0, v;
@@ -86,6 +115,15 @@
         return( 1 );
     }
 
+    /*
+     * Make sure we have a snprintf that correctly zero-terminates
+     */
+    if( run_test_snprintf() != 0 )
+    {
+        mbedtls_printf( "the snprintf implementation is broken\n" );
+        return( 0 );
+    }
+
     if( argc == 2 && strcmp( argv[1], "-quiet" ) == 0 )
         v = 0;
     else
diff --git a/scripts/data_files/error.fmt b/scripts/data_files/error.fmt
index d66f6eb..a097aac 100644
--- a/scripts/data_files/error.fmt
+++ b/scripts/data_files/error.fmt
@@ -42,10 +42,6 @@
 #include <stdio.h>
 
 HEADER_INCLUDED
-#if defined(_MSC_VER) && !defined  snprintf && !defined(EFIX64) && \
-    !defined(EFI32)
-#define  snprintf  _snprintf
-#endif
 
 void mbedtls_strerror( int ret, char *buf, size_t buflen )
 {
@@ -56,8 +52,6 @@
         return;
 
     memset( buf, 0x00, buflen );
-    /* Reduce buflen to make sure MSVC _snprintf() ends with \0 as well */
-    buflen -= 1;
 
     if( ret < 0 )
         ret = -ret;
diff --git a/tests/suites/main_test.function b/tests/suites/main_test.function
index f1ef917..ba13288 100644
--- a/tests/suites/main_test.function
+++ b/tests/suites/main_test.function
@@ -4,11 +4,13 @@
 #include "mbedtls/platform.h"
 #else
 #include <stdio.h>
+#include <stdlib.h>
 #define mbedtls_exit       exit
 #define mbedtls_free       free
-#define mbedtls_calloc    calloc
+#define mbedtls_calloc     calloc
 #define mbedtls_fprintf    fprintf
 #define mbedtls_printf     printf
+#define mbedtls_snprintf   snprintf
 #endif
 
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
@@ -209,6 +211,34 @@
     return( cnt );
 }
 
+static int test_snprintf( size_t n, const char ref_buf[10], int ref_ret )
+{
+    int ret;
+    char buf[10] = "xxxxxxxxx";
+
+    ret = mbedtls_snprintf( buf, n, "%s", "123" );
+    if( ret < 0 || (size_t) ret >= n )
+        ret = -1;
+
+    if( memcmp( ref_buf, buf, sizeof buf ) != 0 ||
+        ref_ret != ret )
+    {
+        return( 1 );
+    }
+
+    return( 0 );
+}
+
+static int run_test_snprintf( void )
+{
+    return( test_snprintf( 0, "xxxxxxxxx",  -1 ) != 0 ||
+            test_snprintf( 1, "\0xxxxxxxx", -1 ) != 0 ||
+            test_snprintf( 2, "1\0xxxxxxx", -1 ) != 0 ||
+            test_snprintf( 3, "12\0xxxxxx", -1 ) != 0 ||
+            test_snprintf( 4, "123\0xxxxx",  3 ) != 0 ||
+            test_snprintf( 5, "123\0xxxxx",  3 ) != 0 );
+}
+
 int main()
 {
     int ret, i, cnt, total_errors = 0, total_tests = 0, total_skipped = 0;
@@ -236,6 +266,15 @@
         return( 1 );
     }
 
+    /*
+     * Make sure we have a snprintf that correctly zero-terminates
+     */
+    if( run_test_snprintf() != 0 )
+    {
+        mbedtls_fprintf( stderr, "the snprintf implementation is broken\n" );
+        return( 0 );
+    }
+
     file = fopen( filename, "r" );
     if( file == NULL )
     {