Created originally on Bitbucket by Dodan (Dodan Mihai)
Changesets for this Pull Request have not been imported, because it had been already declined on Bitbucket. Marked as closed by the import user.
I have changed the criteria allowing a fastpath. Functions that take char pointers as arguments are no longer allowed through the fast path, because they are more prone to segfaulting.(issues/466)
The issue was that the fast path does not verify if the parameters given to a ctype-function match the argument types specified.
This is not a problem if the function exits with an error, because it is handled afterwards (that is why you do not see this type of behaviour for specifying bool instead of c_int, for example). However, string functions (such as strlen) consider that the string end when they encounter the null char in the stack. Since passing a boolean / int or any other type does not null-terminate the string, there was a segfault.
The reason why I didn't eliminate the fast path altogether, is that it is 3x faster than the slowpath. Also, I am not aware of any libc function with other types of parameters that are as prone to segfaulting, so punishing the use of pointers to int/floats etc. seems redundant.
I have run a test to show the before and after effects. It calls strlen (just as in the example) and the abs(c_int) function of stdlib. There is a warmup of 10000 iterations for both tests, and a measured cycle of 5000000 runs. As you can see, the abs function sufferes no penalty, while strlen is 3 times slower, but it does not segfault anymore, but instead exits with ArgumentError, as expected.
Fixed:
#!python
10000 Abs 5000000 1.29707
10000 strlen 5000000 9.35953
Traceback (most recent call last):
File "/home/mihaid/Documents/ctypes/standalone466.py", line 59, in <module>
assert libc.strlen(False) == 5
File "/home/mihaid/pypy2-v5.7.1-linux64/lib_pypy/_ctypes/function.py", line 354, in __call__
self._convert_args(argtypes, args, kwargs))
File "/home/mihaid/pypy2-v5.7.1-linux64/lib_pypy/_ctypes/function.py", line 583, in _convert_args
raise ArgumentError(str(e))
ArgumentError: expected c_char_p instance instead of bool
Before:
#!python
10000 Abs 5000000 1.27580
10000 strlen 5000000 3.05891
Segmentation fault (core dumped)
Also, I have run the ctypes tests in pypy/module/test_lib_pypy/ctypes_tests and I have the same passing ratio as before.
Thank you for your consideration!