Created
July 9, 2015 01:56
-
-
Save isislovecruft/836111acdccfbfb4a284 to your computer and use it in GitHub Desktop.
Implement bzero(3) in ctypes for PyStringObject/PyBytesObject.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2.7 | |
def PyStringObject_ctypes_bzero(string): | |
"""Use ctypes to manipulate the internal value of a PyStringObject (or | |
PyBytesObject, for Python>=2.7.8), setting all the bytes to ``"\x00"`` | |
(``"\0"`` in C), similarly to the libc bzero(3) function. | |
.. note: This function avoids copying the PyStringObject, as CFFI might | |
do, since any changes to one of Python's "immutable" strings would | |
result in a new PyStringObject/PyBytesObject with a different | |
address/id(). | |
To get the offset in memory of the PyStringObject's sval, we must subtract | |
the size (in bytes) for the following internal Python objects. | |
/* Py_ssize_t is a signed integral type such that sizeof(Py_ssize_t) == | |
* sizeof(size_t). C99 doesn't define such a thing directly (size_t is an | |
* unsigned integral type). See PEP 353 for details. | |
*/ | |
#ifdef HAVE_SSIZE_T | |
typedef ssize_t Py_ssize_t; | |
#elif SIZEOF_VOID_P == SIZEOF_SIZE_T | |
typedef Py_intptr_t Py_ssize_t; | |
#define _PyObject_HEAD_EXTRA \ | |
struct _object *_ob_next; \ | |
struct _object *_ob_prev; | |
#define PyObject_HEAD \ | |
_PyObject_HEAD_EXTRA \ | |
Py_ssize_t ob_refcnt; \ | |
struct _typeobject *ob_type; | |
#define PyObject_VAR_HEAD \ | |
PyObject_HEAD \ | |
Py_ssize_t ob_size; /* Number of items in variable part */ | |
typedef struct { | |
PyObject_VAR_HEAD | |
long ob_shash; | |
int ob_sstate; /* Removed in Python 2.7.x */ | |
char ob_sval[1]; | |
/* Invariants: | |
* ob_sval contains space for 'ob_size+1' elements. | |
* ob_sval[ob_size] == 0. | |
* ob_shash is the hash of the string or -1 if not computed yet. | |
* ob_sstate != 0 iff the string object is in stringobject.c's | |
* 'interned' dictionary; in this case the two references | |
* from 'interned' to this object are *not counted* in ob_refcnt. | |
*/ | |
} PyStringObject; | |
:param str string: All bytes within the **string** will be zeroed-out, | |
that is, they will be set to ``"\x00"``. | |
""" | |
import ctypes | |
sizeof_voidp = ctypes.sizeof(ctypes.c_voidp) | |
sizeof_int = ctypes.sizeof(ctypes.c_int) | |
sizeof_long = ctypes.sizeof(ctypes.c_long) | |
# Py_ssize_t (for ob_refcount) can be defined as having the size of | |
# ssize_t (if our compiler and variant of C9* have ssize_t), otherwise | |
# it has the size of "an integer large enough to store a pointer", | |
# a.k.a. C99 intptr_t, but only if the sizeof(intptr_t) is equal to | |
# the sizeof(void*). Since we can't check the size of intptr_t from | |
# ctypes, we'll just fallback to sizeof(void*) and hope for the best. | |
# What could possibly go wrong? | |
sizeof_Py_ssize_t = ctypes.sizeof( | |
ctypes.c_ssize_t if hasattr(ctypes, 'c_ssize_t') else ctypes.c_voidp) | |
# PyStringObjects don't appear to have PyObject_HEAD_EXTRA allocated… | |
offset = (sizeof_Py_ssize_t + # Py_ssize_t ob_refcnt; | |
sizeof_voidp + # struct _typeobject *ob_type; | |
sizeof_Py_ssize_t + # Py_ssize_t ob_size; | |
sizeof_long + # long ob_shash; | |
sizeof_int) # int ob_sstate; | |
for i in range(len(string)): | |
ctypes.c_char.from_address(id(key) + offset + i) = "\x00" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment