首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否可以还原损坏的“interned”字节对象?

是否可以还原损坏的“interned”字节对象?
EN

Stack Overflow用户
提问于 2018-06-05 20:45:42
回答 1查看 375关注 0票数 7

众所周知,小型bytes-objects自动被CPython“实习生”(类似于用于字符串的实习生-function )。更正: As 解释 by @abarnert它更像整数池而不是内部字符串。

是否有可能在内部字节对象被“实验性”第三方库破坏后恢复它们,或者是重新启动内核的唯一方法?

概念的证明可以用Cython>=0.28(Cython>=0.28)来完成:

代码语言:javascript
复制
%%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所建议的那样

代码语言:javascript
复制
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是被实习生的,所以我们可以看到接下来会发生一些不好的事情:

代码语言:javascript
复制
>>> 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进程都在使用这个池。例如:

代码语言:javascript
复制
>>> do_bad_things()
>>> print(b'a')
b'b'
>>> print((97).to_bytes(1, byteorder='little')) #ord('a')=97
b'a'
EN

回答 1

Stack Overflow用户

发布于 2018-06-06 04:54:41

我遵循@abarnert的伟大解释,下面是我在Cython中实现他的想法的方法。

需要考虑的事项:

  1. 这里有一个字节池(就像整数的情况一样),而不是一个动态的结构(就像字符串实习那样)。因此,我们可以强制这个池中的所有字节对象,并确保它们具有正确的值。
  2. 只有字节-通过PyBytes_FromStringAndSizePyBytes_FromString构造的对象使用内部池,所以请确保使用它们。

这将导致以下实施:

代码语言:javascript
复制
%%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)

略有不同(在我看来,这对原提案有利):

  1. 这个版本不需要知道字节对象池是如何构建的,它是一个连续数组。
  2. 没有潜在损坏的字节-对象被使用。

现在:

代码语言:javascript
复制
>>> do_bad_things()
>>> print(b'a')
b'b'

>>> restore_bytes_pool()
>>> print(b'a')
b'a'

为了测试目的,函数腐蚀(几乎)池中的所有对象:

代码语言:javascript
复制
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'
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50708670

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档