Chris AtLee wrote: > On Jun 11, 6:01 pm, Lenard Lindstrom <[EMAIL PROTECTED]> wrote: > [snip snip snip] >>> if __name__ == "__main__": >>> import getpass, os, sys >>> @conv_func >>> def my_conv(nMessages, messages, pResponse, appData): >>> # Create an array of nMessages response objects >>> # Does r get GC'ed after we're all done? >>> r = (pam_response * nMessages)() >> The memory allocated to r is garbage collected immediately after my_conv >> returns. You need to allocate it explicitly using C's calloc or such. >> This assumes pam_start will free the memory for you. >> >> addr = calloc(sizeof(pam_response), nMessages) >> >> addr is the memory address as a Python integer. >> >>> pResponse.contents = cast(r, POINTER(pam_response)) >> pResponse.contents changes the actual value of pResponse, a value on the >> stack. You want to change the value of the pointer pResponse points to: >> >> pResponse[0] = cast(addr, POINTER(pam_response)) >> >> The cast creates a POINTER(pam_reponse) instance with value addr. > > Ahhh, thank you! I never understood how ctypes' pointer.contents > related > to C pointers. So, the following are equivalent? > > int v = 42; v = 42 > int *p = 0; p = cast(0, POINTER(c_int)) > p = &v; p.contents = v > *p = 123; p[0] = 123
Actually int v = 42; v = c_int(42) for p.contents = v to work. 42 is a Python integer. c_int(42) refers to a mutable C integer in memory initialized to 42. Also, the preferred way to create a NULL pointer in ctypes is to call the pointer type without an argument: int *p = 0; p = POINTER(c_int)() > > Using "pResponse[0] = cast(...)" got me part of the way to fixing my > problem. PAM started either crashing or saying authentication had > failed. > The crash was in free(), and some digging around revealed that PAM > tries to > free the response sent by the application, which makes sense. > > My initial attempt to fix this involved wrapping strdup to allocate a > new > copy of a string to send back to PAM. Here's how I wrapped it: > > strdup = libc.strdup > strdup.argstypes = [c_char_p] > strdup.restype = c_char_p > > This still crashed in free(). I took a look at some of the ctypes > regression tests and something made me try this: > > strdup = libc.strdup > strdup.argstypes = [c_char_p] > strdup.restype = POINTER(c_char) # NOT c_char_p !!!! > > This works like a charm. Not sure why though...Does ctypes do > something > special with c_char_p return types? It seems as if Python was freeing > the > result of strdup() when the string was GC'ed, and then PAM would fail > when > trying to free the same memory. > c_char_p implicitly converts to/from a Python string. So strdup with a c_char_p restype returns a copy of the returned C string as a Python string instead of a pointer to the memory allocated by strdup. And I don't know how a Python string is cast to a c_char_p. -- Lenard Lindstrom <[EMAIL PROTECTED]> -- http://mail.python.org/mailman/listinfo/python-list