Python在访问从ctypes返回的结构中的指针时崩溃
我试图访问Python中此函数返回的树:Python在访问从ctypes返回的结构中的指针时崩溃,python,c++,c,ctypes,Python,C++,C,Ctypes,我试图访问Python中此函数返回的树: TokenTreeNode* generateTokenTree(const wchar_t** tokens, const unsigned int tokenCount, const BlockToken* blockTokens, const unsigned int blockTokenCount); TokenTreeNode的定义: typedef struct tree_node_struct { wchar_t* token;
TokenTreeNode* generateTokenTree(const wchar_t** tokens, const unsigned int tokenCount, const BlockToken* blockTokens, const unsigned int blockTokenCount);
TokenTreeNode的定义:
typedef struct tree_node_struct {
wchar_t* token;
size_t childCount;
struct tree_node_struct* parent;
struct tree_node_struct** children;
} TokenTreeNode;
BlockToken的定义:
typedef struct {
const wchar_t* begin;
const wchar_t* end;
} BlockToken;
下面是相应ctypes python接口的代码:
import ctypes
from typing import List
class CBlockToken(ctypes.Structure):
_fields_ = [('begin', ctypes.c_wchar_p),
('end', ctypes.c_wchar_p)]
class CTokenTreeNode(ctypes.Structure):
_fields_ = [('token', ctypes.c_wchar_p),
('childCount', ctypes.c_size_t),
('parent', ctypes.POINTER('CTokenTreeNode')),
('children', ctypes.POINTER(ctypes.POINTER('CTokenTreeNode')))]
def generate_token_tree(tokens: List[str], blockTokens: List[CBlockToken]) -> CTokenTreeNode:
nativelib = ctypes.WinDLL(source_path + '\\nativelib\\x64\\Release\\nativelib.dll')
generateTokenTree = nativelib.generateTokenTree
generateTokenTree.argtype = [
ctypes.POINTER(ctypes.c_wchar_p),
ctypes.c_uint,
ctypes.POINTER(CBlockToken),
ctypes.c_uint
]
generateTokenTree.restype = ctypes.POINTER(CTokenTreeNode)
c_arg_tokens = (ctypes.c_wchar_p * len(tokens))(*tokens)
c_arg_token_count = len(tokens)
c_arg_block_tokens = (CBlockToken * len(blockTokens))(*blockTokens)
c_arg_block_tokens_count = len(blockTokens)
root_node = generateTokenTree(c_arg_tokens,
c_arg_token_count,
c_arg_block_tokens,
c_arg_block_tokens_count)
return root_node.contents
当我试图访问返回的根节点的子节点时,python崩溃
>>> test_tokens = ['var', 'test', '=', '"', 'string', '"']
>>> block_tokens = [parser.CBlockToken('"', '"')]
>>> root_node = parser.generate_token_tree(test_tokens, block_tokens)
>>> root_node.childCount
4
>>> root_node.children[0].contents
python crashes
如果我在C++中访问生成的树,一切都会按预期运行。对我来说,问题似乎是由于某种原因,python不允许访问外部库分配的内存。然而,我不知道如何修复甚至调试这个问题
编辑:根据@MilesBudnek的建议更改了TreeTokenNode.childCount的类型 编辑2: 以下是根据调试器在generateTokenTreeNode()末尾的树的内存布局:- rootNode->children,10 0x000001e3c7454250 {0x000001e3c74544f0 {token=0x000001e3c7456b30 L"var" childCount=0 parent=0x000001e3c7454a90 {...} ...}, ...} tree_node_struct *[10]
+ [0] 0x000001e3c74544f0 {token=0x000001e3c7456b30 L"var" childCount=0 parent=0x000001e3c7454a90 {token=0x0000000000000000 <NULL> ...} ...} tree_node_struct *
+ [1] 0x000001e3c74547f0 {token=0x000001e3c74565e0 L"test" childCount=0 parent=0x000001e3c7454a90 {token=0x0000000000000000 <NULL> ...} ...} tree_node_struct *
+ [2] 0x000001e3c7454130 {token=0x000001e3c537d0e0 L"=" childCount=0 parent=0x000001e3c7454a90 {token=0x0000000000000000 <NULL> ...} ...} tree_node_struct *
- [3] 0x000001e3c7454d30 {token=0x000001e3c7456360 L"\"\"" childCount=1 parent=0x000001e3c7454a90 {token=0x0000000000000000 <NULL> ...} ...} tree_node_struct *
- children 0x000001e3c74569f0 {0x000001e3c7454df0 {token=0x000001e3c74567c0 L"string" childCount=0 parent=0x000001e3c7454d30 {...} ...}} tree_node_struct * *
- 0x000001e3c7454df0 {token=0x000001e3c74567c0 L"string" childCount=0 parent=0x000001e3c7454d30 {token=...} ...} tree_node_struct *
+ token 0x000001e3c74567c0 L"string" wchar_t *
childCount 0 unsigned __int64
+ parent 0x000001e3c7454d30 {token=0x000001e3c7456360 L"\"\"" childCount=1 parent=0x000001e3c7454a90 {token=0x0000000000000000 <NULL> ...} ...} tree_node_struct *
+ children 0x0000000000000000 {???} tree_node_struct * *
-rootNode->children,10 0x000001e3c7454250{0x000001e3c74544f0{token=0x000001e3c7456b30 L“var”childCount=0 parent=0x000001e3c7454a90{…}…},}树节点结构*[10]
+[0]0x000001e3c74544f0{token=0x000001e3c7456b30 L“var”childCount=0 parent=0x000001e3c7454a90{token=0x0000000000000000…}}树节点结构*
+[1]0x000001e3c74547f0{token=0x000001e3c74565e0 L“测试”childCount=0父节点=0x000001e3c7454a90{token=0x0000000000000000…}树节点结构*
+[2]0x000001e3c7454130{token=0x000001e3c537d0e0 L“=”childCount=0 parent=0x000001e3c7454a90{token=0x0000000000000000…}}树\u节点\u结构*
-[3]0x000001e3c7454d30{token=0x000001e3c7456360 L“\”\”childCount=1父节点=0x000001e3c7454a90{token=0x0000000000000000…}}树节点结构*
-子项0x000001e3c74569f0{0x000001e3c7454df0{token=0x000001e3c74567c0 L“string”childCount=0 parent=0x000001e3c7454d30{…}}}树节点结构**
-0x000001e3c7454df0{token=0x000001e3c74567c0 L“string”childCount=0 parent=0x000001e3c7454d30{token=…}…}树节点结构*
+令牌0x000001e3c74567c0 L“字符串”wchar\u t*
childCount 0无符号\uuuu int64
+父节点0x000001e3c7454d30{token=0x000001e3c7456360 L“\”\”childCount=1父节点0x000001e3c7454a90{token=0x0000000000000000…}}树节点结构*
+子项0x0000000000000000{???}树节点结构**
这里的函数是从python代码调用的,我们可以看到,在python访问数据结构之前,内存布局是正确的。如果尝试读取根节点的子节点,则会发生访问冲突。
CTokenTreeNode
的childCount
字段可能应该是ctypes.c\u size\u t
,而不是c\u uint
unsigned int
通常是4个字节,而size\u t
通常是8个字节。@MilesBudnek我改变了这一点,不幸的是它没有任何区别。一个错误是generateTokenTree.argtypes。检查。另外,('parent',ctypes.POINTER('CTokenTreeNode'),
在CTokenTreeNode周围没有引号CTokenTreeNode
的childCount
字段可能应该是ctypes.c\u size\u t
,而不是c\u uint
unsigned int
通常是4个字节,而size\u t
通常是8个字节。@MilesBudnek我改变了这一点,不幸的是它没有任何区别。一个错误是generateTokenTree.argtypes。检查。另外,('parent',ctypes.POINTER('CTokenTreeNode'),
在CTokenTreeNode周围没有引号!