python ctypes 数组数据损坏

python ctypes array data getting corrupted

我有以下文件:

test.h:

extern "C" {

void* createTest();
void getStrings(void* test_ptr, char*** strings, size_t* length);

}

test.cpp:

#include <vector>
#include "test.h"

class Test {
public:
    Test() {
        strings.push_back("test1");
        strings.push_back("test2");
        strings.push_back("test3");
        strings.push_back("test4");
    }
    std::vector<char *>& getStrings() {
        return strings;
    }

private:
    std::vector<char *> strings;
};

void* createTest() {
    return reinterpret_cast<void *>(new Test());
}

void getStrings(void* test_ptr, char*** strings, size_t* length) {
    auto inst = reinterpret_cast<Test *>(test_ptr);
    auto strs = inst->getStrings();
    *strings = strs.data();
    *length = strs.size();
}

test.py:

from ctypes import *
lib = cdll.LoadLibrary("test.so")

test_ptr = c_void_p()
test_ptr = lib.createTest()

strs_arr = POINTER(c_char_p)()
strs_len = c_size_t()

lib.getStrings(test_ptr, byref(strs_arr), byref(strs_len))

for i in range(0, strs_len.value):
    print("var {}: data={}".format(i, strs_arr[i]))

我想要实现的是通过 python 检索从 c++ class 成员获得的字符串数组,但是,看起来数据最终以某种方式损坏了是我在执行 python 文件时得到的:

var 0: data=None
var 1: data=b'\x04'
var 2: data=b'test3'
var 3: data=b'test4'

我正在使用以下指令进行编译:

clang++-12 -fPIC -g -c test.cpp -o test.o
clang++-12 -fPIC -g -shared test.o -o test.so

有人知道我可能做错了什么吗?我试过更改 ctypes 但我总是得到相同的结果。我还尝试使用 gdb 进行调试,并在 getStrings(void* test_ptr, ...) 内设置断点,显示数据在该点仍然完好无损。

getStrings 中,auto 类型推导以某种方式失败。将其更改为:

void getStrings(void* test_ptr, char*** strings, size_t* length) {
    auto inst = reinterpret_cast<Test *>(test_ptr);
    std::vector<char*>& strs = inst->getStrings();
    *strings = strs.data();
    *length = strs.size();
}

似乎解决了这个问题。我发现将第二个参数的 auto 更改为 auto& 也可以正常工作。

现在看清楚了,似乎是auto在检测引用时犹豫不决,因此创建了局部变量,这不可避免地超出了范围,导致了UB。

Relevant part of the standard。另一种选择是使用 decltype(auto).

Relevant post.