Python C模块 – Malloc在特定版本的Python中失败

我正在编写一个Python模块来在O_DIRECT上下文中执行IO。 O_DIRECT的一个限制是你必须读入对应于2.4和2.5内核的4096字节边界的缓冲区,2.6及以上将接受512的任意倍数。

显而易见的内存分配候选是posix_memalign(void **memptr, size_t alignment, size_t size)

在我的代码中,我分配了一个像这样的区域:

 char *buffer = NULL; int mem_ret = posix_memalign((void**)&buffer, alignment, size); if (!buffer) { PyErr_NoMemory(); return NULL; } /* I do some stuff here */ free(buffer); 

当我用python3.2编译和导入模块时,这个(以及未示出的模块的其余部分)工作正常。

当我尝试使用python2.7(我想保持兼容性)时,它会抛出PyErr_NoMemoryexception,而mem_ret == ENOMEM表示它无法分配。

为什么我编译的Python版本会影响posix_memalign的运行方式?

操作系统:Ubuntu 12.04 LTS

编译器:Clang + GCC显示相同的行为

UPDATE

感谢user694733,我现在有了一段代码
然而它工作的事实让我更加困惑:

 #if PY_MAJOR_VERSION >= 3 char *buffer = NULL; int mem_ret = posix_memalign((void**)&buffer, alignment, count); #else void *mem = NULL; int mem_ret = posix_memalign(&mem, alignment, count); char *buffer = (char*)mem; #endif 

任何人都可以解释为什么不正确的第一个块在Python3下运行,但不是2.7,更重要的是为什么正确的第二个块在Python3下不起作用?

更新2

情节越来越浓,已经确定了下面代码的正确forms,我测试了4个不同版本的Python。

 void *mem = NULL; int mem_ret = posix_memalign(&mem, alignment, count); char *buffer = (char*)mem; if (!buffer) { PyErr_NoMemory(); return NULL; } /* Do stuff with buffer */ free(buffer); 

Python 2.7下 :此代码按预期运行。
Python 3.1下 :此代码按预期运行。
Python 3.2下 :此代码生成mem_ret == ENOMEM并为buffer返回NULL
Python 3.3下 :此代码按预期运行。

未包含在Ubuntu存储库中的Python版本是从PPA安装的,位于https://launchpad.net/~fkrull/+archive/deadsnakes

如果要相信版本标记的Python二进制文件,我安装的版本是:

 python2.7 python3.1 python3.2mu (--with-pymalloc --with-wide-unicode) python3.3m (--with-pymalloc) 

在默认的Python3发行版中使用wide-unicode标志会导致此错误吗? 如果是这样,这是怎么回事?

为清楚起见, ENOMEM分配失败将发生在malloc()任何变体中,甚至像malloc(512)那样简单。

要快速解决问题,请坚持使用mmap而不是malloc+memalign

posix_memalign在一个编译环境中可能与另一个编码环境中的代码体不同。 您可以很容易地想象Python 3会对Python 2使用不同的function测试宏。这可能意味着它最终会运行不同的代码。

您可能会查看使用的符号…通常ldd或nm的输出将具有指示实际使用的版本的错位名称。

另外,分配系统调用的strace显示了什么? 我发现这是一种很好的方式来查看传入的参数是否不正确,这可能是获得ENOMEM的原因。