背景
我正在构建importer来加密我的代码。编译时,我会加密pyc
文件中的代码对象。加载时,我使用此自定义的导入程序在执行之前解密代码对象。
由于我的代码是以zip格式捆绑在一起的,所以我决定通过向其内置的zipimport包中添加解密逻辑来修改zipimporter
。
我正在使用Python 3.7
问题
我修改了zimpimport.c并将其变成C扩展名。加密和解密过程运行良好,但我开始看到ImportError
和AttributeError
。例如:
"""module: test.py"""
class Foo:
def bar():
pass
foo = Foo()
// Import Error: can not import name 'foo' from test
// Attribute Error: foo has no attribute bar
服务器启动时,仅在前几分钟内随机发生此错误。因此,我怀疑这是一个多线程问题,并且是由线程看到部分初始化的模块对象引起的。
我尝试过的事情
检查原始c代码后,加载模块的实现是:
mod = PyImport_AddModuleObject(fullname);
// ... some code
mod = PyImport_ExecCodeModuleObject(fullname, code, modpath, NULL);
首先将模块添加到sys.modules
,然后执行一些C代码并最终执行模块代码。如果另一个线程在完成执行模块代码之前读取了sys.modules
,则可以获取ImportError
和AttributeError
。
我只是复制原始实现,并且不使用导入锁。我想它是由外层的解释器处理的,我必须显式地使用导入锁。因此,我用导入锁包装了代码块,如下所示:
#include "import.h"
_PyImport_AcquireLock();
// wrapped code block
_PyImport_ReleaseLock();
我的问题
添加导入锁后,错误仍然发生。我对python c api不熟悉。我是否以正确的方式使用了锁?还有其他可能导致此错误的原因吗?
代码
要进行测试,请将以下文件放在同一文件夹中:
zipimport_zipimporter_load_module_impl
中添加了运行python setup.py build_ext --inplace
,它将生成zzimporter.so
。它的工作方式类似于buit-in zipimport模块。