0

I have a c function as:

extern "C"  __declspec(dllexport) MyStruct foo()
{
    MyStruct s = {0, 0}
    return s;
}

where the MyStruct is define as:

struct MyStruct{
    uInt32   a;
    uInt32   b;
    void *   c;
};

And i am trying to call the function in python, but always get error like:

WindowsError: exception: access violation writing 0x00000000

if i remove void * c from the struct, then it works...

so how should i return the void pointer? thanks!

2
  • 2
    What does your Python code look like? Commented Jul 23, 2012 at 21:33
  • 1
    This is a C bug, not a Python bug. Commented Jul 23, 2012 at 21:45

4 Answers 4

3

This is almost certainly being caused by a disagreement between your C compiler and the ctypes library on the ABI for returning the object. Without seeing your Python code, it's hard to say whether the problem is due to an incorrect Python declaration of the return type, a bug in the ctypes library, or a non-standard ABI chosen by the C compiler.

For the most portable behavior, I'd suggest changing the function to return the object via an out parameter, like so:

extern "C"  __declspec(dllexport) void foo(MyStruct *ret)
{
    MyStruct s = {0, 0}
    *ret = s;
}

And interface with it like so:

class MyStruct(ctypes.Structure):
    _fields_ = [("a", ctypes.c_uint),
                ("b", ctypes.c_uint),
                ("c", ctypes.c_void_p)]

mylib = ctypes.cdll.LoadLibrary('mylibrary')
foo = mylib.foo
foo.argtypes = [ctypes.POINTER(MyStruct)]

x = MyStruct()
foo(ctypes.byref(x))
# x should now have the return value from the C code
Sign up to request clarification or add additional context in comments.

2 Comments

+1 because you obviously know more about the python side of things than I do. I can only evaluate the C code in and of itself.
my python code was really simple as mydll = ctypes.CDLL('mydll'), then mydll.foo() since the c function does not take any input... i think your way works, but only want to point out that byref() only works for ctypes type, not self defined struct
1

I don't see is you allocating your void* c. I don't see that anywhere, yet it seems as though it is being read somewhere later (i.e., access violation writing 0x00000000, a NULL pointer). So, c needs to be initialized to something before dereferencing it.

It seems that the value of c happens to be 0 here, but it doesn't have to be. It doesn't have static storage duration, and you did not initialize it (you only initialized a and b with {0, 0}), so c could have any value. It just so happens that, in my test case, c resides in an area of memory which has been initialized to 0 (even in release). This is not guaranteed.

I would bet you're doing something like:

MyStruct s = foo();
*((some_type*)s.c) = some_value;  // BLAMOOO! c is uninitialized

You have not posted the code which uses the return value, so this is the best guess I can give you.

1 Comment

well, i just wonder can i return a void pointer that equals to NULL to python? i tried to change MyStruct s = {0, 0} to MyStruct s = {0, 0, 0}, still no luck.... my python code is in my comment to Adam‘s reply, anyway, thanks to all for answering my question, all replies are helpful!
0

It would help if you showed your Python code. You need to define the structure and the return type of foo:

from ctypes import *

class MyStruct(Structure):
    _fields_ = [
        ('a',c_int),
        ('b',c_int),
        ('c',c_void_p)]

mydll = CDLL('mydll')
mydll.foo.restype = MyStruct

r = mydll.foo()
print r.a
print r.b
print r.c

Comments

-2

Allocate your structure on the heap and return a pointer to it, rather than allocating it on the stack. When you allocate things on the stack, they are short-lived, i.e., they are deallocated automatically by the machine upon return from the subroutine.

Look up malloc (man malloc) / see here: http://linux.die.net/man/3/malloc

3 Comments

The stack allocation has nothing to do with it. When you return a stack object by value, it gets copied (or constructed in-place, if the compiler uses the return value optimization).
-1 A copy of s is returned, not a pointer to it. So what is invalid here? The only I can think of is that the code is later dereferencing c, which has not been initialized.
OK, yes, I see that my answer is wrong; Ed has the best answer at the moment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.