众所周知,小型bytes-objects自动被CPython“实习生”(类似于用于字符串的实习生-function )。更正: As 解释 by @abarnert它更像整数池而不是内部字符串。
是否有可能在内部字节对象被“实验性”第三方库破坏后恢复它们,或者是重新启动内核的唯一方法?
概念的证明可以用Cython>=0.28(Cython>=0.28)来完成:
%%cython
def do_bad_things():
cdef bytes b=b'a'
cdef const unsigned char[:] safe=b
cdef char *unsafe=<char *> &safe[0] #who needs const and type-safety anyway?
unsafe[0]=98 #replace through `b`或如@jfs通过ctypes所建议的那样
import ctypes
import sys
def do_bad_things():
b = b'a';
(ctypes.c_ubyte * sys.getsizeof(b)).from_address(id(b))[-2] = 98显然,通过滥用C-功能,do_bad_things将不可变的对象b'a'更改为b'b',并且由于这个bytes-object是被实习生的,所以我们可以看到接下来会发生一些不好的事情:
>>> do_bad_things() #b'a' means now b'b'
>>> b'a'==b'b' #wait for a surprise
True
>>> print(b'a') #another one
b'b'可以恢复/清除字节对象池,以便b'a'再次表示b'a'?
请注意:似乎不是每个bytes-creation进程都在使用这个池。例如:
>>> do_bad_things()
>>> print(b'a')
b'b'
>>> print((97).to_bytes(1, byteorder='little')) #ord('a')=97
b'a'发布于 2018-06-06 04:54:41
我遵循@abarnert的伟大解释,下面是我在Cython中实现他的想法的方法。
需要考虑的事项:
PyBytes_FromStringAndSize和PyBytes_FromString构造的对象使用内部池,所以请确保使用它们。这将导致以下实施:
%%cython
from libc.limits cimport UCHAR_MAX
from cpython.bytes cimport PyBytes_FromStringAndSize
cdef replace_first_byte(bytes obj, unsigned char new_value):
cdef const unsigned char[:] safe=obj
cdef unsigned char *unsafe=<unsigned char *> &safe[0]
unsafe[0]=new_value
def restore_bytes_pool():
cdef char[1] ch
#create all possible bytes-objects b`\x00` to b`x255`:
for i in range(UCHAR_MAX+1):
ch[0]=<unsigned char>(i)
obj=PyBytes_FromStringAndSize(ch, 1) #use it so the pool is used
replace_first_byte(obj,i)略有不同(在我看来,这对原提案有利):
现在:
>>> do_bad_things()
>>> print(b'a')
b'b'
>>> restore_bytes_pool()
>>> print(b'a')
b'a'为了测试目的,函数腐蚀(几乎)池中的所有对象:
def corrupt_bytes_pool():
cdef char[1] ch
for i in range(UCHAR_MAX+1):
ch[0]=<unsigned char>(i)
obj=PyBytes_FromStringAndSize(ch, 1)
replace_first_byte(obj,98) #sets all to b'b'https://stackoverflow.com/questions/50708670
复制相似问题