I have a DLL that allocates memory, adding data to the structure. And returns data to the python code. But, got 'Null Pointer Access' in Python code.
C file: (getatt.c) --- generate getatt.dll file after build.
typedef struct _ATTO {
char title[132 + 1];
char val[132 + 1];
} ATT;
__declspec(dllexport) void get_file_attributes(char* psFileName, ATT** *StructAtt, int* iTotalAtt) {
int j = 0;
int iError = NONE;
char cMessage[132 + 1] = "";
int iNumAtt = 5;
StructAtt = (ATT***)malloc(iNumAtt * sizeof(ATT**));
if(StructAtt == NULL) {
fprintf(stderr, "Memory allocation failed\n");
return;
}
if(iNumAtt > 0) {
for(i = 0; i < iNumAtt; i++) {
StructAtt[i] = malloc(sizeof(ATT*));
if(StructAtt[i] == NULL) {
fprintf(stderr, "Memory allocation failed\n");
return ;
}
for(j = 0; j < 1; j++) {
StructAtt[i][j] = (ATT*)malloc(sizeof(ATT));
if(StructAtt[i][j] == NULL) {
fprintf(stderr, "Memory allocation failed\n");
return ;
}
strcpy((StructAtt[i][j])->title, psStructAttInfoTitle[i]); //psStructAttInfoTitle is an array of titles
strcpy((StructAtt[i][j])->val, psStructAttInfoVal[i]); //psStructAttInfoVal is an array of values
sprintf(cMessage, "%s=%s\n", StructAtt[i][j]->title, StructAtt[i][j]->val);
// write_output(cMessage);
}
}
}
// Display values
for(i = 0; i < iNumAtt; i++) {
for(j = 0; j < 1; j++) {
sprintf(message, "%s=%s\n", (StructAtt)[i][j]->title, (StructAtt)[i][j]->val);
write_output(message);
}
}
*iTotalAtt = iNumAtt;
return;
}
Result:
TYPE=0
SUF=C
GROUP=a
OWNER=unknown
NUMSUF=467
Also, I have a python code that access this function:
import ctypes
from ctypes import *
class PY_STRUCT(Structure):
_fields_ = [('title', c_char * 133),
('value', c_char * 133)]
file_name = 'Forest23wd'
file_att_dll = CDLL('./getatt')
file_attribute_dll.get_file_attributes.argtypes = [c_char_p, POINTER(POINTER(POINTER(PY_STRUCT))),POINTER(c_int)]
file_name_str = c_char_p(file_name.encode('utf-8'))
attr_list = POINTER(POINTER(PY_STRUCT))()
total_attr = c_int(0)
file_att_dll.get_file_attributes(file_name_str, byref(attr_list), byref(total_attr))
# Accessing data
print(total_attr.value)
print(attr_list[0][0].contents.title) # ValueError: NULL pointer access...
I got total_attr is 5. This looks good.
I'm expecting attr_list[0][0]
would be "TYPE". But I am getting an error
ValueError: NULL pointer access.
Any idea where am I doing wrong? Any suggestions please.
You need one more level of indirection, and I don't see how attr_list[0][0].contents
would've worked in your code. Since it originally was a POINTER(POINTER(PY_STRUCT))
, attr_list[0][0]
would be a PY_STRUCT
, which doesn't have a .contents
member. Anyway...
In the C code, StructAtt
(an ATT***) needs to be returned, so the function should be:
__declspec(dllexport) void get_file_attributes(char* psFileName, ATT*** *pStructAtt, int* iTotalAtt) {
ATT*** StructAtt = malloc(iNumAtt * sizeof(ATT**)); // don't cast malloc in C
...
*iTotalAtt = iNumAtt;
*pStructAtt = StructAtt;
}
Then, in Python, update .argtypes
and attr_list
:
file_attribute_dll.get_file_attributes.argtypes = [c_char_p, POINTER(POINTER(POINTER(POINTER(PY_STRUCT))),POINTER(c_int)]
...
attr_list = POINTER(POINTER(POINTER(PY_STRUCT)))()