[issue38258] ctypes ignores when a DLL function is called with too many arguments

2019-09-24 Thread Eryk Sun


Eryk Sun  added the comment:

> Just out of curiosity, where is this data coming from?

In general it's just random data on the stack. It's not worth investigating 
where this particular value comes from. It could be the low word of the address 
of a stack-allocated buffer, such as the buffer where ffi_call writes the 
return value.

> This ONLY way to prevent things like this to happen is to actually 
> correctly configure the function:
> ...
> >>> mul_ints.argtypes = (ctypes.c_int16, ctypes.c_int16)

Yes, the docs should explain that TypeError is raised for the wrong number of 
arguments when argtypes is assigned, and it should be noted that cdecl (CDLL) 
allows passing more (but not fewer) arguments than what argtypes defines. As I 
mentioned previously, we could extend this cdecl behavior to stdcall (WinDLL) 
for the x64 architecture, since it's caller cleanup like cdecl.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue38258] ctypes ignores when a DLL function is called with too many arguments

2019-09-24 Thread Sebastian Ernst


Sebastian Ernst  added the comment:

Thanks a lot for the clarification, Eryk. I did not notice that it was 
deprecated behavior.

For the "too many arguments" case I guess this is not an issue. However, just 
for the symmetry of things, I also looked at calling a function with TOO FEW 
arguments. 

```C
int16_t __stdcall __declspec(dllimport) mul_ints(
int16_t a,
int16_t b
)
{
return a * b;
}
```

```python
def test_error_callargs_unconfigured_too_few_args():

dll = ctypes.windll.LoadLibrary('tests/demo_dll.dll')
mul_ints = dll.mul_ints

with pytest.raises(ValueError):
a = mul_ints(7)
```

As expected after your explanation, also no error in CPython 3.8 (i.e. the test 
fails, while is passes on CPython <= 3.7). If I run this manually, I even get a 
"result":

```python
>>> dll = ctypes.windll.LoadLibrary('tests/demo_dll.dll')
>>> mul_ints = dll.mul_ints
>>> a = mul_ints(7)
>>> a
445564 # !
>>> 445564/7 # Just looking at where this result is coming from ...
63652.0
```

Re-starting Python (3.8) and (intentionally) misconfiguring the function 
interestingly also does not change the result:

```python
>>> dll = ctypes.windll.LoadLibrary('tests/demo_dll.dll')
>>> mul_ints = dll.mul_ints
>>> mul_ints.argtypes = (ctypes.c_int16,)
>>> a = mul_ints(7)  
>>> a
445564 # Apparently, this is deterministic?!?
```

Just out of curiosity, where is this data coming from?

This ONLY way to prevent things like this to happen is to actually correctly 
configure the function:

```python
>>> dll = ctypes.windll.LoadLibrary('tests/demo_dll.dll')
>>> mul_ints = dll.mul_ints
>>> mul_ints.argtypes = (ctypes.c_int16, ctypes.c_int16)
>>> mul_ints(7)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: this function takes 2 arguments (1 given)
```

This should very CLEARLY be mentioned in the documentation ...

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue38258] ctypes ignores when a DLL function is called with too many arguments

2019-09-23 Thread Eryk Sun


Eryk Sun  added the comment:

According to the docs, raising ValueError in this case has been a deprecated 
feature since 3.6.2, and the ability to do so no longer exists in 3.8. The 
documentation needs to be updated to reflect the new behavior.

https://docs.python.org/3.8/library/ctypes.html#calling-functions

In issue 35947, the customized libffi_msvc was replaced by standard libffi. 
ffi_call() in libffi_msvc returned a stack cleanup delta. This allowed raising 
ValueError in _call_function_pointer if the delta value was non-zero for an x86 
32-bit stdcall function (callee cleanup). A positive delta implied too many 
arguments, and a negative delta implied too few arguments. The standard libffi 
ffi_call() has no return value, so the code for raising ValueError was removed.

---

On a related note, PyCFuncPtr_call can be relaxed to allow the argument count 
to exceed the length of argtypes for x64 stdcall (but not x86). The 64-bit 
calling convention is the same for cdecl, stdcall, fastcall, and thiscall. It 
uses caller cleanup, like x86 cdecl, so we can skip raising TypeError in this 
case, just like we already do for cdecl.

--
assignee:  -> docs@python
components: +Documentation, Windows
nosy: +docs@python, eryksun, paul.moore, steve.dower, tim.golden, zach.ware
stage:  -> needs patch
versions: +Python 3.9

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue38258] ctypes ignores when a DLL function is called with too many arguments

2019-09-23 Thread Sebastian Ernst


New submission from Sebastian Ernst :

A c-function with the following signature ...

```C
int16_t __stdcall __declspec(dllimport) square_int(
int16_t a
);
```

... is being called with ctypes:

```python
def test_error_callargs_unconfigured_too_many_args():

dll = ctypes.windll.LoadLibrary('tests/demo_dll.dll')
square_int = dll.square_int

with pytest.raises(ValueError):
a = square_int(1, 2, 3)
```

Expected result: If the function is called with too many (positional) arguments 
(in the example 3 instead of 1), a `ValueError` should be raised. This is the 
case for at least CPython 3.4 to 3.7.

Actual result: "Nothing", i.e. no exception. The described test "fails". The 
function is called without an error - with CPython 3.8.0b4.

If this behavior is intended, is has not been (as far as I can tell) documented.

--
components: ctypes
messages: 353021
nosy: smernst
priority: normal
severity: normal
status: open
title: ctypes ignores when a DLL function is called with too many arguments
type: behavior
versions: Python 3.8

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com