Counter-intuitive behavior when using string_at with a c_char_p type.

JT Olds <[email protected]> Wed, 1 Aug 2012 23:07:39 -0600
Newsgroups gmane.comp.python.ctypes
Message-ID <CAPTS6cV0LSgq-isptgnkE87Js2XiF3UaJNmz+2b2Qey7H+Y+yg@mail.gmail.com>
Hey all,

I can't decide if this is a bug or what, but this is very definitely
surprising behavior to me. Basically, if the restype of a C method is
c_char_p instead of c_void_p, even if you don't want null-terminated
strings you get it. Yay!

Given the following program:

    import ctypes
    import ctypes.util

    libc = ctypes.CDLL(ctypes.util.find_library('c'))
    libc.memcpy.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t]
    libc.memcpy.restype = ctypes.c_char_p

    value = "\x01\x00\x01\x02\x03"
    out = ctypes.create_string_buffer(len(value))
    out = libc.memcpy(out, value, len(value))
    out = ctypes.string_at(out, len(value))
    assert len(out) == len(value)
    assert out == value

Note that only the second assertion fails. Both assertions will
succeed if you change libc.memcpy.restype to ctypes.c_void_p.

So what's going on here? I'm not completely sure, but everything after
the null byte gets replaced with garbage if libc.memcpy.restype is
ctypes.c_char_p.

Is this intentional? Is this a bug? It made me tear my hair out for a
few hours today. Note that both of these work:

    assert value == ctypes.string_at(ctypes.cast(value,
ctypes.c_char_p), len(value))
    assert value == ctypes.string_at(ctypes.cast(value,
ctypes.c_void_p), len(value))

-JT

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/