1

我正在测试一个从 C 重写为 Python 的模块,并且遇到了我在职业生涯中见过的一个奇怪的错误。带有测试的有问题的 Python 代码只有三行:

# MATCHERS is a list of compiled regular expression objects defined as a
# global in the top level of the module
print dir(MATCHERS[0])
# diff.Differ is a class implemented in C with thed Python API; zoneA/B Words are
# lists and CompareLines, isJunk, and SetStaticLine are functions
differ = diff.Differ(zoneAWords, zoneBWords, CompareLines, isJunk, SetStaticLine)
# Causes a TypeError
dir(MATCHERS[0])

这三行产生以下输出:

['__class__', '__copy__', '__deepcopy__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'findall', 'finditer', 'flags', 'groupindex', 'groups', 'match', 'pattern', 'scanner', 'search', 'split', 'sub', 'subn']
Traceback (most recent call last):
  File "Diff.py", line 1032, in <module>
    main()
  File "Diff.py", line 1019, in main
    diffs = CompareFiles(sys.argv[1], sys.argv[2])
  File "Diff.py", line 584, in CompareFiles
    print dir(MATCHERS[0])
TypeError: eqTest must be a function

在创建用 C 编写的对象之前打印已编译的正则表达式对象的 dir() 可以正常工作,但之后简单地使用 dir() 会导致 TypeError。据我所知, dir() 没有办法导致 TypeError。TypeError 和与之关联的消息来自我的代码,作为对象的 eqTest 字段的自定义 setter 函数的一部分,但是对 dir() 的调用当然不会尝试将 eqTest 设置为任何内容;它已经在上一行成功设置。

这一切都让我相信 C 代码中出现了问题,从而产生了这种奇怪的行为。我目前的假设是缓冲区溢出;写入超出数组的边界会改变导致这些错误的某些东西。(要求 MATCHERS[0] 匹配一个字符串只会使 Python 崩溃而没有错误消息)我已经检查了一段时间的初始化代码,只是想我会检查是否还有其他可能导致这种情况的原因。

我的代码太长,无法在此处包含,并且在此处的 Pastebin 上;您可以忽略第 434 行之后的所有内容,因为它尚未执行。

4

1 回答 1

2

问题可能是当初始化失败时您的Differ_init函数没有返回。-1setup_differ

您的setup_differ电话py_differ_set_eqTest

static int py_differ_set_eqTest(DIFFER* self, PyObject* value, void* closure)
{
    PyObject* tmp;

    TYPE_CHECK(PyFunction_Check, "eqTest must be a function");
    ASSIGN_MEMBER_NAME(self, value, eqTest);
    return 0;
}

TYPE_CHECK宏在哪里:

#define TYPE_CHECK(typeChecker, msg) if (value != Py_None && !typeChecker(value)) \
    {PyErr_SetString(PyExc_TypeError, msg); return -1;}

问题是setup_differ不检查是py_differ_set_eqTest成功还是失败,即使失败了你也会Differ_init返回。0

现在,当您调用时dir,它会正确打印属性,但在返回之前它可能会检查异常,并查看TypeError由引发的TYPE_CHECK并引发它。

为了解决这个问题,每个函数都应该返回一个值,以便您可以确定是否引发了异常,如果失败则Differ_init应该返回 -1 。setup_differ

于 2013-01-29T19:57:02.353 回答