Skip to content

Commit c946fd3

Browse files
authored
Fixed __new__ segfault. Fixed pgPolygon_FromObject segfault and refactorings. Added a test (#186)
1 parent c5cd1f0 commit c946fd3

File tree

2 files changed

+43
-32
lines changed

2 files changed

+43
-32
lines changed

src_c/polygon.c

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -77,23 +77,27 @@ _pg_polygon_vertices_astuple(pgPolygonBase *poly)
7777
static int
7878
_pgPolygon_InitFromObject(PyObject *obj, pgPolygonBase *init_poly)
7979
{
80-
/* This function always allocates new memory for the vertices, and
81-
* therefore it should be used only when the polygon is not yet
82-
* initialized. */
80+
/* This function initializes a Polygon object. It can resize the memory
81+
* for the vertices if needed, and therefore it should be used only when
82+
* the polygon is not yet initialized. */
8383
Py_ssize_t length;
8484

8585
/* If the Python object is already a pgPolygonBase object, copy the
8686
* relevant information from that object to the init_poly object into
87-
* the new memory. */
87+
* the memory, resize if needed. */
8888
if (pgPolygon_Check(obj)) {
8989
pgPolygonBase *poly = &pgPolygon_AsPolygon(obj);
9090

9191
/* Copy the vertices from the old polygon to the new polygon, while
92-
* also allocating new memory. */
93-
if (!(init_poly->vertices = _pg_new_vertices_from_polygon(poly))) {
94-
PyErr_Clear();
95-
return 0;
92+
* also allocating new memory. Resize the vertices array if needed. */
93+
if (poly->verts_num > 3) {
94+
PyMem_Resize(init_poly->vertices, double, poly->verts_num * 2);
95+
if (!init_poly->vertices) {
96+
return 0;
97+
}
9698
}
99+
memcpy(init_poly->vertices, poly->vertices,
100+
poly->verts_num * 2 * sizeof(double));
97101

98102
init_poly->verts_num = poly->verts_num;
99103
init_poly->c_x = poly->c_x;
@@ -113,10 +117,12 @@ _pgPolygon_InitFromObject(PyObject *obj, pgPolygonBase *init_poly)
113117
if (length >= 3) {
114118
Py_ssize_t i;
115119

116-
/*Allocate memory for the vertices of the polygon*/
117-
init_poly->vertices = PyMem_New(double, length * 2);
118-
if (!init_poly->vertices) {
119-
return 0;
120+
/* Resize the vertices array if needed. */
121+
if (length > 3) {
122+
PyMem_Resize(init_poly->vertices, double, length * 2);
123+
if (!init_poly->vertices) {
124+
return 0;
125+
}
120126
}
121127

122128
/*Extract the x and y coordinates of each vertex and store them in
@@ -171,9 +177,11 @@ _pgPolygon_InitFromObject(PyObject *obj, pgPolygonBase *init_poly)
171177
Py_ssize_t i;
172178

173179
/*Allocate memory for the vertices of the polygon*/
174-
init_poly->vertices = PyMem_New(double, length * 2);
175-
if (!init_poly->vertices) {
176-
return 0;
180+
if (length > 3) {
181+
PyMem_Resize(init_poly->vertices, double, length * 2);
182+
if (!init_poly->vertices) {
183+
return 0;
184+
}
177185
}
178186

179187
/*Extract the x and y coordinates of each vertex and store
@@ -231,12 +239,6 @@ _pgPolygon_InitFromObject(PyObject *obj, pgPolygonBase *init_poly)
231239
PyObject *iter = PyObject_GetIter(obj);
232240
Py_ssize_t i = 0, currently_allocated = 3;
233241

234-
/* Allocate memory for the vertices of the polygon */
235-
init_poly->vertices = PyMem_New(double, 2 * currently_allocated);
236-
if (!init_poly->vertices) {
237-
return 0;
238-
}
239-
240242
/* Extract the x and y coordinates of each vertex and store
241243
them in the init_poly object */
242244
while ((item = PyIter_Next(iter))) {
@@ -356,12 +358,13 @@ pgPolygon_FromObject(PyObject *obj, pgPolygonBase *out, int *was_sequence)
356358

357359
if (pgPolygon_Check(obj)) {
358360
/*Do a shallow copy of the pgPolygonBase object*/
359-
memcpy(out, &pgPolygon_AsPolygon(obj), sizeof(pgPolygonBase));
360361
*was_sequence = 0;
362+
memcpy(out, &pgPolygon_AsPolygon(obj), sizeof(pgPolygonBase));
361363
return 1;
362364
}
363365

364366
if (PySequence_FAST_CHECK(obj)) {
367+
*was_sequence = 1;
365368
PyObject **f_arr = PySequence_Fast_ITEMS(obj);
366369
length = PySequence_Fast_GET_SIZE(obj);
367370

@@ -374,7 +377,7 @@ pgPolygon_FromObject(PyObject *obj, pgPolygonBase *out, int *was_sequence)
374377
return 0;
375378
}
376379

377-
for (i = 0; i < out->verts_num; i++) {
380+
for (i = 0; i < length; i++) {
378381
double x, y;
379382
if (!pg_TwoDoublesFromObj(f_arr[i], &x, &y)) {
380383
PyMem_Free(out->vertices);
@@ -391,22 +394,21 @@ pgPolygon_FromObject(PyObject *obj, pgPolygonBase *out, int *was_sequence)
391394
out->c_x /= length;
392395
out->c_y /= length;
393396

394-
*was_sequence = 1;
395397
return 1;
396398
}
397399
else if (length == 1) {
398400
if (!pgPolygon_FromObject(f_arr[0], out, was_sequence)) {
399401
return 0;
400402
}
401-
*was_sequence = 1;
402403
return 1;
403404
}
404-
405+
/*Length is 0 or 2 -> invalid polygon*/
405406
return 0;
406407
}
407408

408409
else if (PySequence_Check(obj)) {
409410
/* Path for other sequences or Types that count as sequences*/
411+
*was_sequence = 1;
410412
PyObject *tmp = NULL;
411413
length = PySequence_Length(obj);
412414

@@ -437,7 +439,6 @@ pgPolygon_FromObject(PyObject *obj, pgPolygonBase *out, int *was_sequence)
437439
out->c_x /= length;
438440
out->c_y /= length;
439441

440-
*was_sequence = 1;
441442
return 1;
442443
}
443444
else if (length == 1) {
@@ -448,10 +449,9 @@ pgPolygon_FromObject(PyObject *obj, pgPolygonBase *out, int *was_sequence)
448449
return 0;
449450
}
450451
Py_DECREF(tmp);
451-
*was_sequence = 1;
452452
return 1;
453453
}
454-
454+
/*Length is 0 or 2 -> invalid polygon*/
455455
return 0;
456456
}
457457

@@ -521,6 +521,8 @@ pgPolygon_FromObjectFastcall(PyObject *const *args, Py_ssize_t nargs,
521521
else if (nargs >= 3) {
522522
Py_ssize_t i;
523523

524+
*was_sequence = 1;
525+
524526
out->vertices = PyMem_New(double, nargs * 2);
525527
if (!out->vertices) {
526528
return 0;
@@ -542,7 +544,6 @@ pgPolygon_FromObjectFastcall(PyObject *const *args, Py_ssize_t nargs,
542544
out->c_x /= nargs;
543545
out->c_y /= nargs;
544546

545-
*was_sequence = 1;
546547
return 1;
547548
}
548549

@@ -652,8 +653,12 @@ pg_polygon_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
652653
pgPolygonObject *self = (pgPolygonObject *)type->tp_alloc(type, 0);
653654

654655
if (self) {
655-
self->polygon.vertices = NULL;
656-
self->polygon.verts_num = 0;
656+
self->polygon.vertices = PyMem_New(double, 6);
657+
if (!self->polygon.vertices) {
658+
Py_DECREF(self);
659+
return NULL;
660+
}
661+
self->polygon.verts_num = 3;
657662
self->polygon.c_x = 0;
658663
self->polygon.c_y = 0;
659664
self->weakreflist = NULL;

test/test_polygon.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,12 @@ def test_assign_subscript_invalid_assignment(self):
10291029
with self.assertRaises(TypeError):
10301030
poly[-i] = invalid_args[i]
10311031

1032+
def test_polygon___new__(self):
1033+
"""Tests whether the __new__ method works correctly."""
1034+
polygon = Polygon.__new__(Polygon)
1035+
self.assertIsInstance(polygon, Polygon)
1036+
self.assertEqual(polygon.verts_num, 3)
1037+
10321038

10331039
if __name__ == "__main__":
10341040
unittest.main()

0 commit comments

Comments
 (0)