Re: Weird bug? with CFUNCTYPE and glfw

Urs Schulz <[email protected]> Sun, 07 Jul 2013 12:02:33 +0200
Newsgroups gmane.comp.python.ctypes
Message-ID <[email protected]>
Hi again,

UPDATE: Now that I had a theory, what may go wrong here I was able to
write a more minimal example without GLFW that reproduces this
behaviour. Again, Python 3.3.2:

#!/usr/bin/env python3

import ctypes as c

lib = c.CDLL("./libtest.so")

CALLBACK = c.CFUNCTYPE(None)

lib.reg(CALLBACK(lambda: print("lambda")))
lib.call()
def cb():
    print("cb")

lib.call()

and the corresponding C code for libtest.so:

// compile with: gcc -shared -fPIC test.c -o libtest.so
typedef void(* cb)();

cb callback;

void reg(cb callb) {
    callback = callb;
    callback();
}

void call() {
    callback();
}

The output of this is the following:
> lambda
> lambda
> cb

So I thought, this is not even a bug, but the CALLBACK object is simply
droped by Python because it can not know that libtest.so is still
storing a pointer to what ctypes has generated and also ctypes can not
know, that the libtest.so still has a pointer to the callback. When
changing the code to the following:

#!/usr/bin/env python3

import ctypes as c

lib = c.CDLL("./libtest.so")

CALLBACK = c.CFUNCTYPE(None)
callback = CALLBACK(lambda: print("lambda"))
lib.reg(callback)
lib.call()
def cb():
    print("cb")

lib.call()

It works perfectly fine and telling me "lambda" 3 times. With the same
steps I was able to fix the GLFW code. Sorry for bothering you.

Cheers

Am Sonntag, den 07.07.2013, 11:35 +0200 schrieb Urs Schulz:
> Hi folks,
> 
> I found a weird bug (or at least I don't understand whats happening)
> when writing some Python 3 code using GLFW 3.0.1. Unfortunately I was
> not able to reproduce the error with a selfwritten small C library, it
> only occours when using glfw on linux (testet on arch 64 bit).
> 
> I reduced the problem to the following minimal code:
> #!/usr/bin/env python3
> 
> import ctypes as c
> 
> class GLFWwindow(c.Structure):
>     pass
> GLFWwindow_p = c.POINTER(GLFWwindow)
> GLFWkeyfun = c.CFUNCTYPE(None, GLFWwindow_p, c.c_int, c.c_int, c.c_int,
> c.c_int)
> 
> lib = c.CDLL("libglfw.so")
> lib.glfwCreateWindow.restype = GLFWwindow_p
> 
> lib.glfwInit()
> win = lib.glfwCreateWindow(800, 600, "Title".encode(), None, None)
> lib.glfwSetKeyCallback(win, GLFWkeyfun(lambda w, key, scancode, action,
> mods: print(key, action)))
> 
> #def cb(*args):
> #    print(args)
> 
> while True:
>     lib.glfwPollEvents()
> 
> The window is created successfully, but when I press a key I get the
> following errors in the console:
> 
> Traceback (most recent call last):
>   File "_ctypes/callbacks.c", line 260, in 'calling callback function'
> TypeError: 'LP_GLFWwindow' object is not callable
> Traceback (most recent call last):
>   File "_ctypes/callbacks.c", line 260, in 'calling callback function'
> TypeError: 'LP_GLFWwindow' object is not callable
> 
> (this block for each press and release). I don't know why it tries to
> call a LP_GLFWwindow object...
> But if I now uncomment the cb function (and not! changing any other
> thing inside the code) the output becomes even more weird:
> 
> (<__main__.LP_GLFWwindow object at 0x7ff51e03edd0>, 87, 25, 1, 0)
> (<__main__.LP_GLFWwindow object at 0x7ff51e03edd0>, 87, 25, 0, 0)
> 
> But I have never registered cb as a callback to glfwSetKeyCallback.
> 
> So I tried changing to Python 2.7.5. The behaviour changes to this:
> 
> Output without the cb-function:
> 
> > 87 1
> > [1]    1795 segmentation fault (core dumped)  ./test2.py
> 
> and with cb-function:
> 
> > (<__main__.LP_GLFWwindow object at 0x7f72fab86680>, 87, 25, 1, 0)
> > [1]    1758 segmentation fault (core dumped)  ./test2.py
> 
> The code header changed to:
> 
> #!/usr/bin/env python2
> from __future__ import print_function
> 
> the rest of the code is exactly the same.
> 
> I have the following idea that may explain this:
> Python is freeing the lambda function, because GLFWkeyfun does not
> properly increment the reference counter on it. After this it creates
> the cb function, and stores it on the same memory where the lambda lived
> before, so this one gets called instead. But I don't know much about
> Python or ctypes internals so this is just speculation.
> 
> I googled a lot but found nothing on this. I am using Python 3.3.2 and
> GLFW 3.0.1 both in the recent version from the arch repos (64 bit). You
> can find the glfw documentation at [1]. I'm not even sure if this is a
> bug or just missusage of the ctypes module or maybe even a bug inside
> gcc or glfw. If you need any other information (including hardware or
> system information) or require me to test stuff, please tell me.
> 
> Cheers
> 
> References:
> [1] http://www.glfw.org/docs/3.0/group__input.html
> 
> 
> 
> ------------------------------------------------------------------------------
> This SF.net email is sponsored by Windows:
> 
> Build for Windows Store.
> 
> http://p.sf.net/sfu/windows-dev2dev
> _______________________________________________
> ctypes-users mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/ctypes-users



------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev