Skip to content

Commit 2bf120f

Browse files
committed
add argument validation
1 parent 2c44d44 commit 2bf120f

File tree

5 files changed

+70
-24
lines changed

5 files changed

+70
-24
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
if __name__ == "__main__":
77
setup(
88
name="pointers.py",
9-
version="1.3.6",
9+
version="1.3.7",
1010
author="ZeroIntensity",
1111
author_email="<[email protected]>",
1212
description="Bringing the hell of pointers to Python.",

src/pointers/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
DereferenceError,
1515
FreedMemoryError,
1616
InvalidSizeError,
17+
InvalidBindingParameter,
1718
)
1819
from .calloc import calloc, CallocPointer
1920
from .frozen_pointer import to_const_ptr, FrozenPointer

src/pointers/bindings.py

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,17 @@
2020
Dict,
2121
Type,
2222
Iterator,
23+
Tuple,
24+
)
25+
from .c_pointer import (
26+
VoidPointer,
27+
TypedCPointer,
28+
StructPointer,
29+
_BaseCPointer,
2330
)
24-
from .c_pointer import VoidPointer, TypedCPointer, StructPointer
2531
import ctypes
2632
from . import _cstd
33+
from .exceptions import InvalidBindingParameter
2734

2835
if TYPE_CHECKING:
2936
from .struct import Struct
@@ -153,14 +160,12 @@ def _not_null(data: Optional[T]) -> T:
153160
StructMap = Dict[Type[ctypes.Structure], Type["Struct"]]
154161

155162

156-
def _base(
163+
def _decode_response(
164+
res: Any,
165+
struct_map: StructMap,
157166
fn: "ctypes._NamedFuncPointer",
158-
*args,
159-
map_extra: Optional[StructMap] = None,
160167
) -> Any:
161-
res = fn(*args)
162168
res_typ = type(res)
163-
struct_map: StructMap = {**STRUCT_MAP, **(map_extra or {})}
164169

165170
if res_typ.__name__.startswith("LP_"):
166171
struct_type = struct_map.get(getattr(_cstd, res_typ.__name__[3:]))
@@ -185,7 +190,50 @@ def _base(
185190
return res
186191

187192

193+
def _validate_args(
194+
args: Tuple[Any, ...],
195+
fn: "ctypes._NamedFuncPointer",
196+
) -> None:
197+
if not fn.argtypes:
198+
return
199+
200+
for index, (value, typ) in enumerate(zip(args, fn.argtypes)):
201+
n_type = VoidPointer.get_py(typ)
202+
203+
if not isinstance(value, n_type):
204+
v_type = type(value)
205+
206+
if ((v_type is ctypes.c_char_p) and (n_type is bytes)) or (
207+
issubclass(v_type, _BaseCPointer) and (typ is ctypes.c_void_p)
208+
):
209+
continue
210+
211+
raise InvalidBindingParameter(
212+
f"argument {index + 1} got invalid type: expected {n_type.__name__}, got {v_type.__name__}" # noqa
213+
)
214+
215+
216+
def _base(
217+
fn: "ctypes._NamedFuncPointer",
218+
*args,
219+
map_extra: Optional[StructMap] = None,
220+
) -> Any:
221+
_validate_args(args, fn)
222+
res = fn(*args)
223+
224+
return _decode_response(
225+
res,
226+
{**STRUCT_MAP, **(map_extra or {})},
227+
fn,
228+
)
229+
230+
188231
def _make_char_pointer(data: StringLike) -> Union[bytes, ctypes.c_char_p]:
232+
if type(data) not in {VoidPointer, str, bytes}:
233+
raise InvalidBindingParameter(
234+
f"expected a string-like object, got {repr(data)}" # noqa
235+
)
236+
189237
if isinstance(data, bytes):
190238
return data
191239

src/pointers/c_pointer.py

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
TYPE_CHECKING,
1111
Union,
1212
Tuple,
13-
Iterator
13+
Iterator,
1414
)
1515
from .exceptions import InvalidSizeError
1616
from _pointers import add_ref, remove_ref
@@ -147,7 +147,7 @@ def is_mappable(cls, typ: Any) -> bool:
147147
return False
148148

149149
@staticmethod
150-
def get_py(data: Type["ctypes._CData"]) -> Type:
150+
def get_py(data: Type["ctypes._CData"]) -> type:
151151
"""Map the specified C type to a Python type."""
152152
types: Dict[Type["ctypes._CData"], type] = {
153153
ctypes.c_bool: bool,
@@ -223,7 +223,7 @@ def __init__(
223223
data_type: Type[T],
224224
size: int,
225225
alternate_method: bool = True,
226-
decref: bool = True
226+
decref: bool = True,
227227
):
228228
self._alt = alternate_method
229229
super().__init__(address, size)
@@ -241,8 +241,8 @@ def dereference(self) -> T:
241241
ctype = self.get_mapped(self.type)
242242
ptr = (
243243
ctype.from_address(self.address)
244-
if not self._alt else
245-
ctype(self.address)
244+
if not self._alt
245+
else ctype(self.address) # fmt: off
246246
)
247247
return ptr.value # type: ignore
248248

@@ -267,12 +267,7 @@ def __del__(self):
267267

268268
def cast(ptr: VoidPointer, data_type: Type[T]) -> TypedCPointer[T]:
269269
"""Cast a void pointer to a typed pointer."""
270-
return TypedCPointer(
271-
ptr.address,
272-
data_type,
273-
ptr.size,
274-
decref=False
275-
)
270+
return TypedCPointer(ptr.address, data_type, ptr.size, decref=False)
276271

277272

278273
def to_c_ptr(data: T) -> TypedCPointer[T]:
@@ -285,12 +280,7 @@ def to_c_ptr(data: T) -> TypedCPointer[T]:
285280
address = ctypes.addressof(ct)
286281
typ = type(data)
287282

288-
return TypedCPointer(
289-
address,
290-
typ,
291-
ctypes.sizeof(ct),
292-
False
293-
)
283+
return TypedCPointer(address, typ, ctypes.sizeof(ct), False)
294284

295285

296286
def to_struct_ptr(struct: A) -> StructPointer[A]:

src/pointers/exceptions.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"DereferenceError",
77
"FreedMemoryError",
88
"InvalidSizeError",
9+
"InvalidBindingParameter",
910
) # noqa
1011

1112

@@ -49,3 +50,9 @@ class InvalidSizeError(Exception):
4950
"""Raised when trying to move an object of the wrong size to an allocation.""" # noqa
5051

5152
pass
53+
54+
55+
class InvalidBindingParameter(Exception):
56+
"""Raised when an invalid type is passed to the"""
57+
58+
pass

0 commit comments

Comments
 (0)