-
-
Notifications
You must be signed in to change notification settings - Fork 34.6k
gh-143005: prevent incompatible __class__ reassignment for ctypes arrays #143907
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d17521c
670c7a1
32fac41
abfe97e
56903c5
5bb9dfb
8abda12
4dc1890
1ed8361
d784203
ab67884
ff24e32
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -103,6 +103,103 @@ def test_simple(self): | |
| with self.assertRaises(TypeError): | ||
| del ca[0] | ||
|
|
||
| def test_ctypes_array_class_assignment_incompatible(self): | ||
| A = c_long * 3 | ||
| B = c_long * 5 | ||
| x = A(1, 2, 3) | ||
|
|
||
| with self.assertRaises(TypeError): | ||
| x.__class__ = B | ||
|
|
||
| def test_ctypes_array_class_assignment_incompatible_target(self): | ||
| A = c_int * 3 | ||
| class OtherArray(Array): | ||
| _type_ = c_int | ||
| _length_ = 4 # incompatible length | ||
|
|
||
| a = A() | ||
|
|
||
| with self.assertRaises(TypeError): | ||
| a.__class__ = OtherArray | ||
|
|
||
|
|
||
| def test_ctypes_array_class_assignment_zero_length(self): | ||
| A = c_long * 0 | ||
| B = c_long * 1 | ||
| a = A() | ||
|
|
||
| with self.assertRaises(TypeError): | ||
| a.__class__ = B | ||
|
|
||
| def test_ctypes_array_class_assignment_incompatible_element_type(self): | ||
| A = c_int * 3 | ||
| B = c_double * 3 | ||
|
Comment on lines
+135
to
+136
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. c_int and c_double most likely have different size. We need to test different types with the same size. I suggest to unite multiple tests in the same method and use a loop with an array of type pairs: for A, B in [
(c_int * 3, c_double * 3),
(c_long * 3, c_double * 3),
(c_longlong * 3, c_double * 3),
...
]:
with self.subTest(A=A, B=B):
a = A()
with self.assertRaises(TypeError):
a.__class__ = BYou can also use |
||
| a = A() | ||
|
|
||
| with self.assertRaises(TypeError): | ||
| a.__class__ = B | ||
|
|
||
| def test_ctypes_array_class_assignment_signed_unsigned(self): | ||
| A = c_long * 3 | ||
| B = c_ulonglong * 3 | ||
|
Comment on lines
+143
to
+144
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. c_long and c_ulonglong can also have different size. Should not we test c_long with c_longlong. |
||
| a = A() | ||
|
|
||
| with self.assertRaises(TypeError): | ||
| a.__class__ = B | ||
|
|
||
| def test_ctypes_array_class_assignment_compatible(self): | ||
| A = c_int * 3 | ||
| class SameArray(Array): | ||
| _type_ = c_int | ||
| _length_ = 3 | ||
| a = A(1, 2, 3) | ||
| a.__class__ = SameArray | ||
|
|
||
| def test_ctypes_array_class_assignment_non_ctypes_target(self): | ||
| A = c_int * 3 | ||
| a = A() | ||
| class Dummy: | ||
| pass | ||
|
|
||
| with self.assertRaises(TypeError): | ||
| a.__class__ = Dummy | ||
|
|
||
| def test_ctypes_array_class_assignment_abstract_target(self): | ||
| A = c_int * 3 | ||
| a = A() | ||
| AbstractArray = PyCArrayType.__new__(PyCArrayType, "AbstractArray", (Array,), {}) | ||
|
|
||
| with self.assertRaises(TypeError): | ||
| a.__class__ = AbstractArray | ||
|
|
||
| def test_ctypes_array_class_assignment_same_size_ints(self): | ||
| if sizeof(c_int) != sizeof(c_long): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
| self.skipTest("sizes differ on this platform") | ||
| A = c_int * 3 | ||
| B = c_long * 3 | ||
| a = A(1, 2, 3) | ||
| a.__class__ = B | ||
|
|
||
| def test_ctypes_array_class_assignment_structs(self): | ||
| class S1(Structure): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it work for different structs with the same definition? |
||
| _fields_ = [("x", c_int)] | ||
| A = S1 * 2 | ||
| B = S1 * 2 | ||
| a = A() | ||
| a.__class__ = B | ||
|
|
||
| def test_ctypes_array_class_assignment_pointer_arrays(self): | ||
| from ctypes import POINTER | ||
| A = POINTER(c_int) * 2 | ||
| B = POINTER(c_int) * 2 | ||
| a = A() | ||
| a.__class__ = B | ||
|
|
||
| def test_ctypes_array_from_param_incompatible(self): | ||
| A = c_int * 3 | ||
| with self.assertRaises(TypeError): | ||
| A.from_param(object()) | ||
|
|
||
| def test_step_overflow(self): | ||
| a = (c_int * 5)() | ||
| a[3::sys.maxsize] = (1,) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Fix a memory safety issue in ctypes arrays by rejecting ``__class__`` | ||
| assignment to incompatible array types. |
Uh oh!
There was an error while loading. Please reload this page.