]> granicus.if.org Git - python/commitdiff
This patch turns the Python API mismatch notice into a standard
authorMarc-André Lemburg <mal@egenix.com>
Tue, 31 Jul 2001 13:24:44 +0000 (13:24 +0000)
committerMarc-André Lemburg <mal@egenix.com>
Tue, 31 Jul 2001 13:24:44 +0000 (13:24 +0000)
Python warning which can be catched by means of the Python warning
framework.

It also adds two new APIs which hopefully make it easier for Python
to switch to buffer overflow safe [v]snprintf() APIs for error
reporting et al. The two new APIs are PyOS_snprintf() and
PyOS_vsnprintf() and work just like the standard ones in many
C libs. On platforms which have snprintf(), the native APIs are used,
on all other an emulation with snprintf() tries to do its best.

Include/pyerrors.h
Makefile.pre.in
Python/modsupport.c
Python/mysnprintf.c [new file with mode: 0644]

index 3c57e2f03144fda23d53ff789c0d1415997a6f02..bfc36ae03ac1b45f47f0dc5c04b4ec6496c967be 100644 (file)
@@ -106,6 +106,22 @@ extern DL_IMPORT(void) PyErr_SetInterrupt(void);
 extern DL_IMPORT(void) PyErr_SyntaxLocation(char *, int);
 extern DL_IMPORT(PyObject *) PyErr_ProgramText(char *, int);
        
+/* These APIs aren't really part of the error implementation, but
+   often needed to format error messages; the native C lib APIs are
+   not available on all platforms, which is why we provide emulations
+   for those platforms in Python/mysnprintf.c */
+#if defined(MS_WIN32) && !defined(HAVE_SNPRINTF)
+# define HAVE_SNPRINTF
+# define snprintf _snprintf
+# define vsnprintf _vsnprintf
+#endif
+#ifndef HAVE_SNPRINTF
+extern DL_IMPORT(int) PyOS_snprintf(char *str, size_t size, const char  *format, ...);
+extern DL_IMPORT(int) PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va);
+#else
+# define PyOS_vsnprintf        vsnprintf
+# define PyOS_snprintf snprintf
+#endif
 
 #ifdef __cplusplus
 }
index 3ca3397abd9fdaf7ffa2ee32efbe885178c741fc..9fbf29d8f0cbaf05bdc6b85569275002c1da96d4 100644 (file)
@@ -214,6 +214,7 @@ PYTHON_OBJS=        \
                Python/marshal.o \
                Python/modsupport.o \
                Python/mystrtoul.o \
+               Python/mysnprintf.o \
                Python/pyfpe.o \
                Python/pystate.o \
                Python/pythonrun.o \
index 08685898da222abc3bb06f06a92595661eb2df78..eb0818cc95cae3b7bbe68c4d0c6aa8493b2fce74 100644 (file)
@@ -26,8 +26,8 @@ char *_Py_PackageContext = NULL;
 */
 
 static char api_version_warning[] =
-"WARNING: Python C API version mismatch for module %s:\n\
 This Python has API version %d, module %s has version %d.\n";
+"Python C API version mismatch for module %.100s:\
This Python has API version %d, module %.100s has version %d.";
 
 PyObject *
 Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
@@ -37,9 +37,15 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
        PyMethodDef *ml;
        if (!Py_IsInitialized())
            Py_FatalError("Interpreter not initialized (version mismatch?)");
-       if (module_api_version != PYTHON_API_VERSION)
-               fprintf(stderr, api_version_warning,
-                       name, PYTHON_API_VERSION, name, module_api_version);
+       if (module_api_version != PYTHON_API_VERSION) {
+               char message[512];
+               PyOS_snprintf(message, sizeof(message), 
+                             api_version_warning, name, 
+                             PYTHON_API_VERSION, name, 
+                             module_api_version);
+               if (PyErr_Warn(PyExc_RuntimeWarning, message)) 
+                       return NULL;
+       }
        if (_Py_PackageContext != NULL) {
                char *p = strrchr(_Py_PackageContext, '.');
                if (p != NULL && strcmp(name, p+1) == 0) {
diff --git a/Python/mysnprintf.c b/Python/mysnprintf.c
new file mode 100644 (file)
index 0000000..e6c3fce
--- /dev/null
@@ -0,0 +1,96 @@
+
+#include "Python.h"
+
+/* snprintf() emulation for platforms which don't have it (yet). 
+   
+   Return value
+
+       The number of characters printed (not including the trailing
+       `\0' used to end output to strings) or a negative number in
+       case of an error.
+
+       PyOS_snprintf and PyOS_vsnprintf do not write more than size
+       bytes (including the trailing '\0').
+
+       If the output would have been truncated, they return the number
+       of characters (excluding the trailing '\0') which would have
+       been written to the final string if enough space had been
+       available. This is inline with the C99 standard.
+
+*/
+
+#include <ctype.h>
+
+#ifndef HAVE_SNPRINTF
+
+static
+int myvsnprintf(char *str, size_t size, const char  *format, va_list va)
+{
+    char *buffer = PyMem_Malloc(size + 512);
+    int len;
+    
+    if (buffer == NULL)
+       return -1;
+    len = vsprintf(buffer, format, va);
+    if (len < 0) {
+       PyMem_Free(buffer);
+       return len;
+    }
+    len++;
+    if (len > size + 512)
+       Py_FatalError("Buffer overflow in PyOS_snprintf/PyOS_vsnprintf");
+    if (len > size) {
+       PyMem_Free(buffer);
+       return len - 1;
+    }
+    memcpy(str, buffer, len);
+    PyMem_Free(buffer);
+    return len - 1;
+}
+
+int PyOS_snprintf(char *str, size_t size, const  char  *format, ...)
+{
+    int rc;
+    va_list va;
+
+    va_start(va, format);
+    rc = myvsnprintf(str, size, format, va);
+    va_end(va);
+    return rc;
+}
+
+int PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
+{
+    return myvsnprintf(str, size, format, va);
+}
+
+#else
+
+/* Make sure that a C API is included in the lib */
+
+#ifdef PyOS_snprintf
+# undef PyOS_snprintf
+#endif
+
+int PyOS_snprintf(char *str, size_t size, const  char  *format, ...)
+{
+    int rc;
+    va_list va;
+
+    va_start(va, format);
+    rc = vsnprintf(str, size, format, va);
+    va_end(va);
+    return rc;
+}
+
+#ifdef PyOS_vsnprintf
+# undef PyOS_vsnprintf
+#endif
+
+int PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
+{
+    return vsnprintf(str, size, format, va);
+}
+
+#endif
+