summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/ctypes/__init__.py25
-rw-r--r--Lib/ctypes/test/test_byteswap.py65
-rw-r--r--Lib/ctypes/test/test_cfuncs.py2
-rw-r--r--Lib/ctypes/test/test_loading.py29
-rw-r--r--Lib/ctypes/test/test_sizes.py3
-rw-r--r--Modules/_ctypes/_ctypes.c93
-rw-r--r--Modules/_ctypes/callproc.c64
7 files changed, 190 insertions, 91 deletions
diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py
index dd0f640..a005594 100644
--- a/Lib/ctypes/__init__.py
+++ b/Lib/ctypes/__init__.py
@@ -304,10 +304,11 @@ class CDLL(object):
raise AttributeError, name
return self.__getitem__(name)
- def __getitem__(self, name):
- func = self._FuncPtr(name, self)
- func.__name__ = name
- setattr(self, name, func)
+ def __getitem__(self, name_or_ordinal):
+ func = self._FuncPtr((name_or_ordinal, self))
+ if not isinstance(name_or_ordinal, (int, long)):
+ func.__name__ = name_or_ordinal
+ setattr(self, name_or_ordinal, func)
return func
class PyDLL(CDLL):
@@ -384,21 +385,29 @@ if _os.name in ("nt", "ce"):
_pointer_type_cache[None] = c_void_p
-# functions
-
-from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, cast
-
if sizeof(c_uint) == sizeof(c_void_p):
c_size_t = c_uint
elif sizeof(c_ulong) == sizeof(c_void_p):
c_size_t = c_ulong
+# functions
+
+from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
+
## void *memmove(void *, const void *, size_t);
memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
## void *memset(void *, int, size_t)
memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
+def PYFUNCTYPE(restype, *argtypes):
+ class CFunctionType(_CFuncPtr):
+ _argtypes_ = argtypes
+ _restype_ = restype
+ _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
+ return CFunctionType
+cast = PYFUNCTYPE(py_object, c_void_p, py_object)(_cast_addr)
+
_string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
def string_at(ptr, size=0):
"""string_at(addr[, size]) -> string
diff --git a/Lib/ctypes/test/test_byteswap.py b/Lib/ctypes/test/test_byteswap.py
index 1b31f90..55a264c 100644
--- a/Lib/ctypes/test/test_byteswap.py
+++ b/Lib/ctypes/test/test_byteswap.py
@@ -2,6 +2,7 @@ import sys, unittest, struct, math
from binascii import hexlify
from ctypes import *
+from ctypes.test import is_resource_enabled
def bin(s):
return hexlify(buffer(s)).upper()
@@ -149,7 +150,7 @@ class Test(unittest.TestCase):
self.failUnless(c_char.__ctype_le__ is c_char)
self.failUnless(c_char.__ctype_be__ is c_char)
- def test_struct_fields(self):
+ def test_struct_fields_1(self):
if sys.byteorder == "little":
base = BigEndianStructure
else:
@@ -198,17 +199,20 @@ class Test(unittest.TestCase):
pass
self.assertRaises(TypeError, setattr, S, "_fields_", [("s", T)])
- # crashes on solaris with a core dump.
- def X_test_struct_fields(self):
+ def test_struct_fields_2(self):
+ # standard packing in struct uses no alignment.
+ # So, we have to align using pad bytes.
+ #
+ # Unaligned accesses will crash Python (on those platforms that
+ # don't allow it, like sparc solaris).
if sys.byteorder == "little":
base = BigEndianStructure
- fmt = ">bhid"
+ fmt = ">bxhid"
else:
base = LittleEndianStructure
- fmt = "<bhid"
+ fmt = "<bxhid"
class S(base):
- _pack_ = 1 # struct with '<' or '>' uses standard alignment.
_fields_ = [("b", c_byte),
("h", c_short),
("i", c_int),
@@ -218,5 +222,54 @@ class Test(unittest.TestCase):
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
self.failUnlessEqual(bin(s1), bin(s2))
+ if is_resource_enabled("unaligned_access"):
+
+ def test_unaligned_nonnative_struct_fields(self):
+ if sys.byteorder == "little":
+ base = BigEndianStructure
+ fmt = ">b h xi xd"
+ else:
+ base = LittleEndianStructure
+ fmt = "<b h xi xd"
+
+ class S(base):
+ _pack_ = 1
+ _fields_ = [("b", c_byte),
+
+ ("h", c_short),
+
+ ("_1", c_byte),
+ ("i", c_int),
+
+ ("_2", c_byte),
+ ("d", c_double)]
+
+ s1 = S(0x12, 0x1234, 0, 0x12345678, 0, 3.14)
+ s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
+ self.failUnlessEqual(bin(s1), bin(s2))
+
+ def test_unaligned_native_struct_fields(self):
+ if sys.byteorder == "little":
+ fmt = "<b h xi xd"
+ else:
+ base = LittleEndianStructure
+ fmt = ">b h xi xd"
+
+ class S(Structure):
+ _pack_ = 1
+ _fields_ = [("b", c_byte),
+
+ ("h", c_short),
+
+ ("_1", c_byte),
+ ("i", c_int),
+
+ ("_2", c_byte),
+ ("d", c_double)]
+
+ s1 = S(0x12, 0x1234, 0, 0x12345678, 0, 3.14)
+ s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
+ self.failUnlessEqual(bin(s1), bin(s2))
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/ctypes/test/test_cfuncs.py b/Lib/ctypes/test/test_cfuncs.py
index 7c2b28b..6e0798d 100644
--- a/Lib/ctypes/test/test_cfuncs.py
+++ b/Lib/ctypes/test/test_cfuncs.py
@@ -179,7 +179,7 @@ else:
def __getattr__(self, name):
if name[:2] == '__' and name[-2:] == '__':
raise AttributeError, name
- func = self._FuncPtr("s_" + name, self)
+ func = self._FuncPtr(("s_" + name, self))
setattr(self, name, func)
return func
diff --git a/Lib/ctypes/test/test_loading.py b/Lib/ctypes/test/test_loading.py
index 80564b8..5a76bb4 100644
--- a/Lib/ctypes/test/test_loading.py
+++ b/Lib/ctypes/test/test_loading.py
@@ -17,8 +17,11 @@ class LoaderTest(unittest.TestCase):
name = "libc.so"
elif sys.platform == "sunos5":
name = "libc.so"
+ elif sys.platform.startswith("netbsd"):
+ name = "libc.so"
else:
name = "libc.so.6"
+## print (sys.platform, os.name)
cdll.load(name)
self.assertRaises(OSError, cdll.load, self.unknowndll)
@@ -37,5 +40,31 @@ class LoaderTest(unittest.TestCase):
cdll.find(name)
self.assertRaises(OSError, cdll.find, self.unknowndll)
+ def test_load_library(self):
+ if os.name == "nt":
+ windll.load_library("kernel32").GetModuleHandleW
+ windll.LoadLibrary("kernel32").GetModuleHandleW
+ WinDLL("kernel32").GetModuleHandleW
+ elif os.name == "ce":
+ windll.load_library("coredll").GetModuleHandleW
+ windll.LoadLibrary("coredll").GetModuleHandleW
+ WinDLL("coredll").GetModuleHandleW
+
+ def test_load_ordinal_functions(self):
+ if os.name in ("nt", "ce"):
+ import _ctypes_test
+ dll = WinDLL(_ctypes_test.__file__)
+ # We load the same function both via ordinal and name
+ func_ord = dll[2]
+ func_name = dll.GetString
+ # addressof gets the address where the function pointer is stored
+ a_ord = addressof(func_ord)
+ a_name = addressof(func_name)
+ f_ord_addr = c_void_p.from_address(a_ord).value
+ f_name_addr = c_void_p.from_address(a_name).value
+ self.failUnlessEqual(hex(f_ord_addr), hex(f_name_addr))
+
+ self.failUnlessRaises(AttributeError, dll.__getitem__, 1234)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/ctypes/test/test_sizes.py b/Lib/ctypes/test/test_sizes.py
index 6fb9ca0..208c00e 100644
--- a/Lib/ctypes/test/test_sizes.py
+++ b/Lib/ctypes/test/test_sizes.py
@@ -20,5 +20,8 @@ class SizesTestCase(unittest.TestCase):
self.failUnlessEqual(8, sizeof(c_int64))
self.failUnlessEqual(8, sizeof(c_uint64))
+ def test_size_t(self):
+ self.failUnlessEqual(sizeof(c_void_p), sizeof(c_size_t))
+
if __name__ == "__main__":
unittest.main()
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 604c590..0be8f69 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -2388,6 +2388,11 @@ static PPROC FindAddress(void *handle, char *name, PyObject *type)
address = (PPROC)GetProcAddress(handle, name);
if (address)
return address;
+
+ if (((size_t)name & ~0xFFFF) == 0) {
+ return NULL;
+ }
+
/* It should not happen that dict is NULL, but better be safe */
if (dict==NULL || dict->flags & FUNCFLAG_CDECL)
return address;
@@ -2493,6 +2498,28 @@ _validate_paramflags(PyTypeObject *type, PyObject *paramflags)
return 1;
}
+static int
+_get_name(PyObject *obj, char **pname)
+{
+#ifdef MS_WIN32
+ if (PyInt_Check(obj) || PyLong_Check(obj)) {
+ /* We have to use MAKEINTRESOURCEA for Windows CE.
+ Works on Windows as well, of course.
+ */
+ *pname = MAKEINTRESOURCEA(PyInt_AsUnsignedLongMask(obj) & 0xFFFF);
+ return 1;
+ }
+#endif
+ if (PyString_Check(obj) || PyUnicode_Check(obj)) {
+ *pname = PyString_AsString(obj);
+ return pname ? 1 : 0;
+ }
+ PyErr_SetString(PyExc_TypeError,
+ "function name must be string or integer");
+ return 0;
+}
+
+
static PyObject *
CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
@@ -2504,7 +2531,7 @@ CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
void *handle;
PyObject *paramflags = NULL;
- if (!PyArg_ParseTuple(args, "sO|O", &name, &dll, &paramflags))
+ if (!PyArg_ParseTuple(args, "(O&O)|O", _get_name, &name, &dll, &paramflags))
return NULL;
if (paramflags == Py_None)
paramflags = NULL;
@@ -2529,9 +2556,14 @@ CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
#ifdef MS_WIN32
address = FindAddress(handle, name, (PyObject *)type);
if (!address) {
- PyErr_Format(PyExc_AttributeError,
- "function '%s' not found",
- name);
+ if ((size_t)name & ~0xFFFF)
+ PyErr_Format(PyExc_AttributeError,
+ "function '%s' not found",
+ name);
+ else
+ PyErr_Format(PyExc_AttributeError,
+ "function ordinal %d not found",
+ name);
return NULL;
}
#else
@@ -2608,8 +2640,9 @@ CFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds)
"O" - must be a callable, creates a C callable function
two or more argument forms (the third argument is a paramflags tuple)
- "sO|O" - function name, dll object (with an integer handle)
- "is|O" - vtable index, method name, creates callable calling COM vtbl
+ "(sO)|..." - (function name, dll object (with an integer handle)), paramflags
+ "(iO)|..." - (function ordinal, dll object (with an integer handle)), paramflags
+ "is|..." - vtable index, method name, creates callable calling COM vtbl
*/
static PyObject *
CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
@@ -2622,14 +2655,13 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (PyTuple_GET_SIZE(args) == 0)
return GenericCData_new(type, args, kwds);
- /* Shouldn't the following better be done in __init__? */
- if (2 <= PyTuple_GET_SIZE(args)) {
+ if (1 <= PyTuple_GET_SIZE(args) && PyTuple_Check(PyTuple_GET_ITEM(args, 0)))
+ return CFuncPtr_FromDll(type, args, kwds);
+
#ifdef MS_WIN32
- if (PyInt_Check(PyTuple_GET_ITEM(args, 0)))
- return CFuncPtr_FromVtblIndex(type, args, kwds);
+ if (2 <= PyTuple_GET_SIZE(args) && PyInt_Check(PyTuple_GET_ITEM(args, 0)))
+ return CFuncPtr_FromVtblIndex(type, args, kwds);
#endif
- return CFuncPtr_FromDll(type, args, kwds);
- }
if (1 == PyTuple_GET_SIZE(args)
&& (PyInt_Check(PyTuple_GET_ITEM(args, 0))
@@ -4351,6 +4383,42 @@ string_at(const char *ptr, Py_ssize_t size)
return PyString_FromStringAndSize(ptr, size);
}
+static int
+cast_check_pointertype(PyObject *arg)
+{
+ StgDictObject *dict;
+
+ if (PointerTypeObject_Check(arg))
+ return 1;
+ dict = PyType_stgdict(arg);
+ if (dict) {
+ if (PyString_Check(dict->proto)
+ && (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) {
+ /* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
+ return 1;
+ }
+ }
+ PyErr_Format(PyExc_TypeError,
+ "cast() argument 2 must be a pointer type, not %s",
+ PyType_Check(arg)
+ ? ((PyTypeObject *)arg)->tp_name
+ : arg->ob_type->tp_name);
+ return 0;
+}
+
+static PyObject *
+cast(void *ptr, PyObject *ctype)
+{
+ CDataObject *result;
+ if (0 == cast_check_pointertype(ctype))
+ return NULL;
+ result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
+ if (result == NULL)
+ return NULL;
+ /* Should we assert that result is a pointer type? */
+ memcpy(result->b_ptr, &ptr, sizeof(void *));
+ return (PyObject *)result;
+}
#ifdef CTYPES_UNICODE
static PyObject *
@@ -4486,6 +4554,7 @@ init_ctypes(void)
PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove));
PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
PyModule_AddObject(m, "_string_at_addr", PyLong_FromVoidPtr(string_at));
+ PyModule_AddObject(m, "_cast_addr", PyLong_FromVoidPtr(cast));
#ifdef CTYPES_UNICODE
PyModule_AddObject(m, "_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
#endif
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index 9d9e322..c019af7 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -1423,71 +1423,7 @@ set_conversion_mode(PyObject *self, PyObject *args)
}
#endif
-static char cast_doc[] =
-"cast(cobject, ctype) -> ctype-instance\n\
-\n\
-Create an instance of ctype, and copy the internal memory buffer\n\
-of cobject to the new instance. Should be used to cast one type\n\
-of pointer to another type of pointer.\n\
-Doesn't work correctly with ctypes integers.\n";
-
-static int cast_check_pointertype(PyObject *arg, PyObject **pobj)
-{
- StgDictObject *dict;
-
- if (PointerTypeObject_Check(arg)) {
- *pobj = arg;
- return 1;
- }
- dict = PyType_stgdict(arg);
- if (dict) {
- if (PyString_Check(dict->proto)
- && (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) {
- /* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
- *pobj = arg;
- return 1;
- }
- }
- if (PyType_Check(arg)) {
- PyErr_Format(PyExc_TypeError,
- "cast() argument 2 must be a pointer type, not %s",
- ((PyTypeObject *)arg)->tp_name);
- } else {
- PyErr_Format(PyExc_TypeError,
- "cast() argument 2 must be a pointer type, not a %s",
- arg->ob_type->tp_name);
- }
- return 0;
-}
-
-static PyObject *cast(PyObject *self, PyObject *args)
-{
- PyObject *obj, *ctype;
- struct argument a;
- CDataObject *result;
-
- /* We could and should allow array types for the second argument
- also, but we cannot use the simple memcpy below for them. */
- if (!PyArg_ParseTuple(args, "OO&:cast", &obj, &cast_check_pointertype, &ctype))
- return NULL;
- if (-1 == ConvParam(obj, 1, &a))
- return NULL;
- result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
- if (result == NULL) {
- Py_XDECREF(a.keep);
- return NULL;
- }
- // result->b_size
- // a.ffi_type->size
- memcpy(result->b_ptr, &a.value,
- min(result->b_size, (int)a.ffi_type->size));
- Py_XDECREF(a.keep);
- return (PyObject *)result;
-}
-
-
PyMethodDef module_methods[] = {
- {"cast", cast, METH_VARARGS, cast_doc},
#ifdef CTYPES_UNICODE
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
#endif