python中的ctypes在mems中崩溃

2024-10-01 17:27:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试图从内存like it is suggested in here中删除密码字符串。在

我写了一个小片段:

import ctypes, sys

def zerome(string):
    location = id(string) + 20
    size     = sys.getsizeof(string) - 20
    #memset =  ctypes.cdll.msvcrt.memset
    # For Linux, use the following. Change the 6 to whatever it is on your computer.
    print ctypes.string_at(location, size)
    memset =  ctypes.CDLL("libc.so.6").memset
    memset(location, 0, size)
    print "Clearing 0x%08x size %i bytes" % (location, size)
    print ctypes.string_at(location, size)

a = "asdasd"

zerome(a)

奇怪的是,这段代码和IPython配合得很好

^{pr2}$

但是Python崩溃了:

[8] oz123@yenitiny:~ $ python a.py 
Segmentation fault
[9] oz123@yenitiny:~ $

有什么想法为什么?在

我用Python2.7.3测试了DebianWheezy。在

小更新…

代码可以在CentOS 6.2和Python2.6.6上运行。 代码在使用python2.6.8的Debian上崩溃了。 我试着思考为什么它在CentOS上有效,而不是在Debian上。唯一的原因是, 哪来了一个即时的不同,就是我的德比安是多拱门和半人马 在我的老笔记本电脑上运行。在

因此,我重新启动了CentOS-latop并在上面加载了Debian-wheezzy。 该代码适用于Debian哮喘病,它不是多拱形的。 因此,我怀疑我在Debian上的配置有点问题。。。在


Tags: the代码sizestringissysitlocation
1条回答
网友
1楼 · 发布于 2024-10-01 17:27:22

ctypes已经有了一个memset函数,因此不必为libc/msvcrt函数创建函数指针。另外,20字节用于普通的32位平台。在64位系统上可能是36个字节。以下是PyStringObject的布局:

typedef struct {
    Py_ssize_t ob_refcnt;         // 4|8 bytes
    struct _typeobject *ob_type;  // 4|8 bytes
    Py_ssize_t ob_size;           // 4|8 bytes
    long ob_shash;                // 4|8 bytes (4 on 64-bit Windows)
    int ob_sstate;                // 4 bytes
    char ob_sval[1];
} PyStringObject; 

所以在32位系统上可以是5*4=20字节,在64位Linux上可以是8*4+4=36字节,在64位Windows上可以是8*3+4*2=32字节。因为字符串不是用垃圾收集头跟踪的,所以可以使用sys.getsizeof。一般来说,如果您不想包含GC头的大小(在内存中,它实际上在从id获得的对象基址之前),那么就使用对象的__sizeof__方法。至少这是我经验中的一个普遍规律。在

您只需要从对象大小中减去缓冲区大小。CPython中的字符串以null结尾,因此只需在其长度上加1即可获得缓冲区大小。例如:

^{pr2}$

编辑

更好的选择是定义PyStringObject结构。这样可以方便地检查ob_sstate。如果它大于0,那就意味着字符串被截取了,正常的做法是引发一个异常。单字符字符串以及代码对象中的字符串常量(仅由ASCII字母和下划线组成)以及解释器内部用于名称(变量名、属性)的字符串。在

from ctypes import *

class PyStringObject(Structure):
    _fields_ = [
      ('ob_refcnt', c_ssize_t),
      ('ob_type', py_object),
      ('ob_size', c_ssize_t),
      ('ob_shash', c_long),
      ('ob_sstate', c_int),
      # ob_sval varies in size
      # zero with memset is simpler
    ]

def zerostr(s):
    """zero a non-interned string"""
    if not isinstance(s, str):
        raise TypeError(
          "expected str object, not %s" % type(s).__name__)

    s_obj = PyStringObject.from_address(id(s))
    if s_obj.ob_sstate > 0:
        raise RuntimeError("cannot zero interned string")

    s_obj.ob_shash = -1  # not hashed yet
    offset = sizeof(PyStringObject)
    memset(id(s) + offset, 0, len(s))

例如:

>>> s = 'abcd' # interned by code object
>>> zerostr(s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 10, in zerostr
RuntimeError: cannot zero interned string

>>> s = raw_input() # not interned
abcd
>>> zerostr(s)
>>> s
'\x00\x00\x00\x00'

相关问题 更多 >

    热门问题