[pypy-svn] r73399 - in pypy/branch/cpython-extension/pypy/module/cpyext: . include test

fijal at codespeak.net fijal at codespeak.net
Mon Apr 5 03:32:56 CEST 2010


Author: fijal
Date: Mon Apr  5 03:32:54 2010
New Revision: 73399

Added:
   pypy/branch/cpython-extension/pypy/module/cpyext/include/mysnprintf.c
   pypy/branch/cpython-extension/pypy/module/cpyext/include/pythonrun.c
   pypy/branch/cpython-extension/pypy/module/cpyext/misc.py   (contents, props changed)
Modified:
   pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py
   pypy/branch/cpython-extension/pypy/module/cpyext/api.py
   pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
   pypy/branch/cpython-extension/pypy/module/cpyext/include/pythonrun.h
   pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_pyerrors.py
Log:
include more stuff from CPython. I believe I should test it while I'm at
adding it...


Modified: pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py	Mon Apr  5 03:32:54 2010
@@ -51,6 +51,7 @@
 import pypy.module.cpyext.mapping
 import pypy.module.cpyext.iterator
 import pypy.module.cpyext.unicodeobject
+import pypy.module.cpyext.misc
 
 # now that all rffi_platform.Struct types are registered, configure them
 api.configure_types()

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/api.py	Mon Apr  5 03:32:54 2010
@@ -556,7 +556,9 @@
                                include_dir / "pyerrors.c",
                                include_dir / "modsupport.c",
                                include_dir / "getargs.c",
-                               include_dir / "stringobject.c"],
+                               include_dir / "stringobject.c",
+                               include_dir / "mysnprintf.c",
+                               include_dir / "pythonrun.c"],
         separate_module_sources = [code],
         export_symbols=export_symbols_eci,
         **kwds

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h	Mon Apr  5 03:32:54 2010
@@ -12,6 +12,7 @@
 #define SIZEOF_VOID_P sizeof(void *)
 #define WITH_DOC_STRINGS
 #define HAVE_UNICODE
+#define INT_MAX (1 << (8 * sizeof(int) - 1))
 
 /* Compat stuff */
 #ifndef _WIN32
@@ -56,6 +57,7 @@
 #include <assert.h>
 #include <locale.h>
 #include <ctype.h>
+#include <stdlib.h>
 
 #include "boolobject.h"
 #include "floatobject.h"

Added: pypy/branch/cpython-extension/pypy/module/cpyext/include/mysnprintf.c
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/mysnprintf.c	Mon Apr  5 03:32:54 2010
@@ -0,0 +1,105 @@
+#include "Python.h"
+#include <ctype.h>
+
+/* snprintf() wrappers.  If the platform has vsnprintf, we use it, else we
+   emulate it in a half-hearted way.  Even if the platform has it, we wrap
+   it because platforms differ in what vsnprintf does in case the buffer
+   is too small:  C99 behavior is to return the number of characters that
+   would have been written had the buffer not been too small, and to set
+   the last byte of the buffer to \0.  At least MS _vsnprintf returns a
+   negative value instead, and fills the entire buffer with non-\0 data.
+
+   The wrappers ensure that str[size-1] is always \0 upon return.
+
+   PyOS_snprintf and PyOS_vsnprintf never write more than size bytes
+   (including the trailing '\0') into str.
+
+   If the platform doesn't have vsnprintf, and the buffer size needed to
+   avoid truncation exceeds size by more than 512, Python aborts with a
+   Py_FatalError.
+
+   Return value (rv):
+
+	When 0 <= rv < size, the output conversion was unexceptional, and
+	rv characters were written to str (excluding a trailing \0 byte at
+	str[rv]).
+
+	When rv >= size, output conversion was truncated, and a buffer of
+	size rv+1 would have been needed to avoid truncation.  str[size-1]
+	is \0 in this case.
+
+	When rv < 0, "something bad happened".  str[size-1] is \0 in this
+	case too, but the rest of str is unreliable.  It could be that
+	an error in format codes was detected by libc, or on platforms
+	with a non-C99 vsnprintf simply that the buffer wasn't big enough
+	to avoid truncation, or on platforms without any vsnprintf that
+	PyMem_Malloc couldn't obtain space for a temp buffer.
+
+   CAUTION:  Unlike C99, str != NULL and size > 0 are required.
+*/
+
+int
+PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
+{
+	int len;  /* # bytes written, excluding \0 */
+#ifdef HAVE_SNPRINTF
+#define _PyOS_vsnprintf_EXTRA_SPACE 1
+#else
+#define _PyOS_vsnprintf_EXTRA_SPACE 512
+	char *buffer;
+#endif
+	assert(str != NULL);
+	assert(size > 0);
+	assert(format != NULL);
+	/* We take a size_t as input but return an int.  Sanity check
+	 * our input so that it won't cause an overflow in the
+         * vsnprintf return value or the buffer malloc size.  */
+	if (size > INT_MAX - _PyOS_vsnprintf_EXTRA_SPACE) {
+		len = -666;
+		goto Done;
+	}
+
+#ifdef HAVE_SNPRINTF
+	len = vsnprintf(str, size, format, va);
+#else
+	/* Emulate it. */
+	buffer = PyMem_MALLOC(size + _PyOS_vsnprintf_EXTRA_SPACE);
+	if (buffer == NULL) {
+		len = -666;
+		goto Done;
+	}
+
+	len = vsprintf(buffer, format, va);
+	if (len < 0)
+		/* ignore the error */;
+
+	else if ((size_t)len >= size + _PyOS_vsnprintf_EXTRA_SPACE)
+		Py_FatalError("Buffer overflow in PyOS_snprintf/PyOS_vsnprintf");
+
+	else {
+		const size_t to_copy = (size_t)len < size ?
+					(size_t)len : size - 1;
+		assert(to_copy < size);
+		memcpy(str, buffer, to_copy);
+		str[to_copy] = '\0';
+	}
+	PyMem_FREE(buffer);
+#endif
+Done:
+	if (size > 0)
+		str[size-1] = '\0';
+	return len;
+#undef _PyOS_vsnprintf_EXTRA_SPACE
+}
+
+int
+PyOS_snprintf(char *str, size_t size, const  char  *format, ...)
+{
+	int rc;
+	va_list va;
+
+	va_start(va, format);
+	rc = PyOS_vsnprintf(str, size, format, va);
+	va_end(va);
+	return rc;
+}

Added: pypy/branch/cpython-extension/pypy/module/cpyext/include/pythonrun.c
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/pythonrun.c	Mon Apr  5 03:32:54 2010
@@ -0,0 +1,31 @@
+
+#include "Python.h"
+
+void
+Py_FatalError(const char *msg)
+{
+	fprintf(stderr, "Fatal Python error: %s\n", msg);
+	fflush(stderr); /* it helps in Windows debug build */
+
+#ifdef MS_WINDOWS
+	{
+		size_t len = strlen(msg);
+		WCHAR* buffer;
+		size_t i;
+
+		/* Convert the message to wchar_t. This uses a simple one-to-one
+		conversion, assuming that the this error message actually uses ASCII
+		only. If this ceases to be true, we will have to convert. */
+		buffer = alloca( (len+1) * (sizeof *buffer));
+		for( i=0; i<=len; ++i)
+			buffer[i] = msg[i];
+		OutputDebugStringW(L"Fatal Python error: ");
+		OutputDebugStringW(buffer);
+		OutputDebugStringW(L"\n");
+	}
+#ifdef _DEBUG
+	DebugBreak();
+#endif
+#endif /* MS_WINDOWS */
+	abort();
+}

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/pythonrun.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/pythonrun.h	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/pythonrun.h	Mon Apr  5 03:32:54 2010
@@ -6,6 +6,7 @@
 extern "C" {
 #endif
 
+  void Py_FatalError(const char *msg);
 
 #ifdef __cplusplus
 }

Added: pypy/branch/cpython-extension/pypy/module/cpyext/misc.py
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/misc.py	Mon Apr  5 03:32:54 2010
@@ -0,0 +1,14 @@
+
+from pypy.module.cpyext.api import cpython_api_c
+
+ at cpython_api_c()
+def Py_FatalError():
+    pass
+
+ at cpython_api_c()
+def PyOS_snprintf():
+    pass
+
+ at cpython_api_c()
+def PyOS_vsnprintf():
+    pass

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py	Mon Apr  5 03:32:54 2010
@@ -1,12 +1,16 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import cpython_api, cpython_struct, \
-        METH_STATIC, METH_CLASS, METH_COEXIST, CANNOT_FAIL
+        METH_STATIC, METH_CLASS, METH_COEXIST, CANNOT_FAIL, cpython_api_c
 from pypy.module.cpyext.pyobject import PyObject, register_container
 from pypy.interpreter.module import Module
 from pypy.module.cpyext.methodobject import W_PyCFunctionObject, PyCFunction_NewEx, PyDescr_NewMethod, PyMethodDef, PyCFunction
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.interpreter.error import OperationError
 
+ at cpython_api_c()
+def PyModule_AddObject():
+    pass
+
 def PyImport_AddModule(space, name):
     w_name = space.wrap(name)
     w_mod = space.wrap(Module(space, w_name))

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_pyerrors.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_pyerrors.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_pyerrors.py	Mon Apr  5 03:32:54 2010
@@ -1,7 +1,9 @@
 from pypy.module.cpyext.state import State
 from pypy.module.cpyext.test.test_api import BaseApiTest
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
-from pypy.rpython.lltypesystem import rffi
+from pypy.rpython.lltypesystem import rffi, ll2ctypes
+
+from pypy.interpreter.gateway import interp2app
 
 class TestExceptions(BaseApiTest):
     def test_GivenExceptionMatches(self, space, api):
@@ -55,6 +57,17 @@
 
 
 class AppTestFetch(AppTestCpythonExtensionBase):
+    def setup_class(cls):
+        AppTestCpythonExtensionBase.setup_class.im_func(cls)
+        space = cls.space
+
+        def set_errno(num):
+            import pdb
+            pdb.set_trace()
+            ll2ctypes.TLS.errno = num
+        
+        cls.w_set_errno = space.wrap(interp2app(set_errno, unwrap_spec=[int]))
+    
     def test_occurred(self):
         module = self.import_extension('foo', [
             ("check_error", "METH_NOARGS",
@@ -78,13 +91,12 @@
         module = self.import_extension('foo', [
                 ("set_from_errno", "METH_NOARGS",
                  '''
-                 int close(int);
-                 close(-1);
                  PyErr_SetFromErrno(PyExc_OSError);
                  return NULL;
                  '''),
                 ])
         try:
+            self.set_errno(errno.EBADF)
             module.set_from_errno()
         except OSError, e:
             assert e.errno == errno.EBADF



More information about the Pypy-commit mailing list