Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将C二进制缓冲区转换为它’;Python字符串中的十六进制表示法?_Python_C_Python 3.x_Cython_Pypy - Fatal编程技术网

如何将C二进制缓冲区转换为它’;Python字符串中的十六进制表示法?

如何将C二进制缓冲区转换为它’;Python字符串中的十六进制表示法?,python,c,python-3.x,cython,pypy,Python,C,Python 3.x,Cython,Pypy,众所周知,pysha3与pypy不兼容,因为它已经3年没有维护了,所以我不得不自己修改它 当然,一个正确的方法是用纯python代码执行完全重写(这也会导致比当前代码更快的实现),但我缺乏做这件事所需的密码学和背景数学知识,并且使用它的程序非常需要列表(需要一个不带gil的python3进行多线程处理,或者需要一个带jit的python3) 必须由C代码调用的单点故障: static PyObject* _Py_strhex(const char* argbuf, const Py_ssize_

众所周知,pysha3与pypy不兼容,因为它已经3年没有维护了,所以我不得不自己修改它

当然,一个正确的方法是用纯python代码执行完全重写(这也会导致比当前代码更快的实现),但我缺乏做这件事所需的密码学和背景数学知识,并且使用它的程序非常需要列表(需要一个不带gil的python3进行多线程处理,或者需要一个带jit的python3)

必须由C代码调用的单点故障:

static PyObject*
_Py_strhex(const char* argbuf, const Py_ssize_t arglen)
{
    static const char *hexdigits = "0123456789abcdef";

    PyObject *retval;
#if PY_MAJOR_VERSION >= 3
    Py_UCS1 *retbuf;
#else
    char *retbuf;
#endif
    Py_ssize_t i, j;

    assert(arglen >= 0);
    if (arglen > PY_SSIZE_T_MAX / 2)
        return PyErr_NoMemory();

#if PY_MAJOR_VERSION >= 3
    retval = PyUnicode_New(arglen * 2, 127);
    if (!retval)
            return NULL;
    retbuf = PyUnicode_1BYTE_DATA(retval);
#else
    retval = PyString_FromStringAndSize(NULL, arglen * 2);
    if (!retval)
            return NULL;
    retbuf = PyString_AsString(retval);
    if (!retbuf) {
            Py_DECREF(retval);
            return NULL;
    }
#endif
    /* make hex version of string, taken from shamodule.c */
    for (i=j=0; i < arglen; i++) {
        unsigned char c;
        c = (argbuf[i] >> 4) & 0xf;
        retbuf[j++] = hexdigits[c];
        c = argbuf[i] & 0xf;
        retbuf[j++] = hexdigits[c];
    }

    return retval;
}
但是它似乎触发了一个分段错误,包括编译和使用官方的Python实现。并且使用官方的PyPy二进制文件,我没有gdb的调试符号,所以我不知道为什么

(gdb) bt
#0  0x00007ffff564cd00 in pypy_g_text_w__pypy_interpreter_baseobjspace_W_Root () from /usr/lib64/pypy3.6-v7.2.0-linux64/bin/libpypy3-c.so
#1  0x00007ffff5d721a8 in pypy_g_getattr () from /usr/lib64/pypy3.6-v7.2.0-linux64/bin/libpypy3-c.so
#2  0x00007ffff543a8bd in pypy_g_dispatcher_15 () from /usr/lib64/pypy3.6-v7.2.0-linux64/bin/libpypy3-c.so
#3  0x00007ffff5ab909b in pypy_g_wrapper_second_level.star_2_14 () from /usr/lib64/pypy3.6-v7.2.0-linux64/bin/libpypy3-c.so
#4  0x00007fffd7212372 in _Py_strhex.2738 () from /usr/lib64/pypy3.6-v7.2.0-linux64/site-packages/pysha3-1.0.3.dev1-py3.6-linux-x86_64.egg/_pysha3.pypy3-72-x86_64-linux-gnu.so
#5  0x00007fffd7217990 in _sha3_sha3_224_hexdigest_impl.2958 () from /usr/lib64/pypy3.6-v7.2.0-linux64/site-packages/pysha3-1.0.3.dev1-py3.6-linux-x86_64.egg/_pysha3.pypy3-72-x86_64-linux-gnu.so
#6  0x00007ffff5be2170 in pypy_g_generic_cpy_call__StdObjSpaceConst_funcPtr_SomeI_5 () from /usr/lib64/pypy3.6-v7.2.0-linux64/bin/libpypy3-c.so
#7  0x00007ffff54b25cd in pypy_g.call_1 () from /usr/lib64/pypy3.6-v7.2.0-linux64/bin/libpypy3-c.so
#8  0x00007ffff56715b9 in pypy_g_BuiltinCodePassThroughArguments1_funcrun_obj () from /usr/lib64/pypy3.6-v7.2.0-linux64/bin/libpypy3-c.so
#9  0x00007ffff56ffc06 in pypy_g_call_valuestack__AccessDirect_None () from /usr/lib64/pypy3.6-v7.2.0-linux64/bin/libpypy3-c.so
#10 0x00007ffff5edb29b in pypy_g_CALL_METHOD__AccessDirect_star_1 () from /usr/lib64/pypy3.6-v7.2.0-linux64/bin/libpypy3-c.so

将默认Linux堆栈深度增加到65Mb不会改变发生segfault的递归深度,因此,即使堆栈深度大于200,这似乎与堆栈溢出无关。

就Cython而言,它比您想象的要简单:

cdef Py_strhex(const char* argbuf, const Py_ssize_t arglen):
    return (argbuf[:arglen]).hex()
基本上,您不需要
malloc
(这会导致内存泄漏,因为它缺少一个
free
),也不需要
memcpy
argbuf[:arglen]
创建一个具有适当长度的
字节
对象(制作数据副本)

这在CPython上确实有效。在PyPy2上,它生成了
AttributeError:“str”对象没有属性“hex”
,这对于Python2来说是正确的。我可以想象,如果它产生分段错误,它会发生在
AttributeError
之前,所以这很有希望。我没有现成的PyPy3


编辑

我现在已经在Py3上测试了我的代码,如下所示:

# extra Cython code just to call the function
def test():
    cdef const char* a = "0123456789"
    return Py_strhex(a,10)
然后从Python:

import modulename
modulename.test()
这在没有分段错误的情况下运行良好;因此我非常确信这段代码很好

我不知道你是如何调用Cython代码的,因为你没有说;但是Cython不会生成C代码,目的是复制一个单独的函数。它生成一个模块,该模块需要导入(在模块导入过程中设置了一些东西)。具体来说,Cython在模块初始化期间设置一个字符串表,包括用于查找属性的字符串
“hex”
。要正确使用此代码,而不是将generate Cython代码的副本转储到C文件中。在Python 3中这样做有点复杂,可能不适合您的目的


我将此答案保留为当前状态,因为我相信它是正确的,并且问题发生在您未指定的部分。很可能它对您没有用处,您可以随意忽略它。

确定找到了我使用此变体所要查找的内容。 这不会在所有编译器上都起作用,并且仅与Python3兼容,但它会在其所依赖的程序上与pysha3实现部分PyPy兼容性(某些测试可能会失败,因为返回了错误的哈希值):

static PyObject * _Py_strhex(const char* argbuf, const Py_ssize_t arglen) {
    static const char *hexdigits = "0123456789abcdef";

    assert(arglen >= 0);

    if (arglen > PY_SSIZE_T_MAX / 2)
        return PyErr_NoMemory();

    const Py_ssize_t len=arglen*2;
    char retbuf[len+1];
    retbuf[len+1]=0;

    /* make hex version of string, taken from shamodule.c */
    for (Py_ssize_t i=0,j=0; i < arglen; i++) {
        retbuf[j++] = hexdigits[(argbuf[i] >> 4) & 0xf];
        retbuf[j++] = hexdigits[argbuf[i] & 0xf];
    }

    return PyUnicode_FromStringAndSize(retbuf,len);
}
static PyObject*\u Py\u strhex(const char*argbuf,const Py\u ssize\u t arglen){
静态常量字符*hexdigits=“0123456789abcdef”;
断言(arglen>=0);
如果(arglen>PY\u SSIZE\u T\u MAX/2)
返回PyErr_nomery();
常数Py_ssize_t len=arglen*2;
char-retbuf[len+1];
retbuf[len+1]=0;
/*制作字符串的十六进制版本,取自shamodule.c*/
对于(Py_ssize_t i=0,j=0;i>4)和0xf];
retbuf[j++]=十六进制数字[argbuf[i]&0xf];
}
从stringandsize(retbuf,len)返回PyUnicode_;
}

有没有可能将您的代码库更新到Python 3.6或更高版本?@Selcuk pypypy支持Python 3.6,但仅在Python级别。在C级别,它的兼容性仍处于3.2级别。即使是最新版本的,也缺少运行pysha3的函数。对不起,我说的是使用Python 3.6附带的内置
hashlib.sha3
。@Selcuk它是为了实现sha3的keccak变体,以便与以太坊兼容,所以不幸的是它不兼容。项目本身不使用pysha3:它被许多pip依赖项使用,所以解决这个问题会更简单。我不知道你为什么说在C级它仍然处于3.2级。也许它错过了一个特定的API乐趣但是如果您报告它,我们会修复这个bug。如果argbuf被传递到堆栈,这不会失败吗(因为垃圾收集器稍后会尝试释放它) ? 当然,我使用的是PyPy3的最新版本。但正如您在回溯中看到的,SEGFULT的发生是因为试图调用Interpeter来查找要执行的函数。字符串拥有自己的内存。这会创建一个临时字符串,其中包含
argbuf
(可以安全地超过
argbuf
,但在这种情况下不需要)。从它派生的十六进制字符串也是独立的,并且拥有自己的内存。从内存管理的角度来看,只要调用函数时
argbuf
有效就可以了。恐怕这只是试图回答问题“如何编写Cython函数将
const char*
转换为hex”是问题的一部分。我真的无法诊断pypypy内部问题!正如回溯所示,如果在不调用python getattr(这也意味着不使用Cython)的情况下使用完整的C语言,听起来像是真正的问题.我的意思是用与Cpython 3.2兼容的全C语言编写(我不知道如何实现)。如果Cython代码仍然产生seg错误,那么我想我帮不了你;我会很快删除我的答案。没有可能仍然可以编辑它。我可以做的是使用C字符串转换为十六进制,然后转换为python字符串。这归结为一个问题:如何使用C
static PyObject * _Py_strhex(const char* argbuf, const Py_ssize_t arglen) {
    static const char *hexdigits = "0123456789abcdef";

    assert(arglen >= 0);

    if (arglen > PY_SSIZE_T_MAX / 2)
        return PyErr_NoMemory();

    const Py_ssize_t len=arglen*2;
    char retbuf[len+1];
    retbuf[len+1]=0;

    /* make hex version of string, taken from shamodule.c */
    for (Py_ssize_t i=0,j=0; i < arglen; i++) {
        retbuf[j++] = hexdigits[(argbuf[i] >> 4) & 0xf];
        retbuf[j++] = hexdigits[argbuf[i] & 0xf];
    }

    return PyUnicode_FromStringAndSize(retbuf,len);
}