Skip to content

Commit fd2bcae

Browse files
committed
FIx PySequence_AsVectorCoords and discourage usage
1 parent 584da82 commit fd2bcae

File tree

1 file changed

+36
-29
lines changed

1 file changed

+36
-29
lines changed

src_c/math.c

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ RealNumber_Check(PyObject *obj);
125125
static double
126126
PySequence_GetItem_AsDouble(PyObject *seq, Py_ssize_t index);
127127
static int
128-
PySequence_AsVectorCoords(PyObject *seq, double *const coords,
129-
const Py_ssize_t size);
128+
pg_VectorCoordsFromObjOldDontUseInNewCode(PyObject *seq, double *const coords,
129+
Py_ssize_t size);
130130
static int
131131
pgVectorCompatible_Check(PyObject *obj, Py_ssize_t dim);
132132
static int
@@ -397,13 +397,26 @@ PySequence_GetItem_AsDouble(PyObject *seq, Py_ssize_t index)
397397
return value;
398398
}
399399

400+
/* Use pg_VectorCoordsFromObj instead of this function. That does exact dim
401+
* checking.
402+
* Note that this function sets a python exception on failures */
400403
static int
401-
PySequence_AsVectorCoords(PyObject *seq, double *const coords,
402-
const Py_ssize_t size)
404+
pg_VectorCoordsFromObjOldDontUseInNewCode(PyObject *seq, double *const coords,
405+
Py_ssize_t size)
403406
{
404407
Py_ssize_t i;
405408

409+
/* This codepath does not do exact size checking, but for compat reasons
410+
* we are gonna keep it as it is */
406411
if (pgVector_Check(seq)) {
412+
Py_ssize_t seq_dim = ((pgVector *)seq)->dim;
413+
if (size > seq_dim) {
414+
/* Prevent undefined behaviour by consistently 0-ing extra dims */
415+
for (i = seq_dim; i < size; ++i) {
416+
coords[i] = 0.0;
417+
}
418+
size = seq_dim;
419+
}
407420
memcpy(coords, ((pgVector *)seq)->coords, sizeof(double) * size);
408421
return 1;
409422
}
@@ -464,8 +477,7 @@ pgVectorCompatible_Check(PyObject *obj, Py_ssize_t dim)
464477
// copies vector coordinates into "coords" array of size >= dim
465478
// managed by caller. Returns 0 if obj is not compatible or an error
466479
// occurred. If 0 is returned, the error flag will not normally be set.
467-
// Callers should set error themselves. This function is a combo of
468-
// pgVectorCompatible_Check and PySequence_AsVectorCoords
480+
// Callers should set error themselves.
469481
static int
470482
pg_VectorCoordsFromObj(PyObject *obj, Py_ssize_t dim, double *const coords)
471483
{
@@ -1129,7 +1141,7 @@ vector_SetSlice(pgVector *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
11291141
}
11301142

11311143
len = ihigh - ilow;
1132-
if (!PySequence_AsVectorCoords(v, new_coords, len)) {
1144+
if (!pg_VectorCoordsFromObjOldDontUseInNewCode(v, new_coords, len)) {
11331145
return -1;
11341146
}
11351147

@@ -1250,7 +1262,8 @@ vector_ass_subscript(pgVector *self, PyObject *key, PyObject *value)
12501262
double seqitems[VECTOR_MAX_SIZE];
12511263
Py_ssize_t cur, i;
12521264

1253-
if (!PySequence_AsVectorCoords(value, seqitems, slicelength)) {
1265+
if (!pg_VectorCoordsFromObjOldDontUseInNewCode(value, seqitems,
1266+
slicelength)) {
12541267
return -1;
12551268
}
12561269
for (cur = start, i = 0; i < slicelength; cur += step, i++) {
@@ -1381,7 +1394,7 @@ vector_richcompare(PyObject *o1, PyObject *o2, int op)
13811394
vec = (pgVector *)o2;
13821395
other = o1;
13831396
}
1384-
if (!pgVectorCompatible_Check(other, vec->dim)) {
1397+
if (!pg_VectorCoordsFromObj(other, vec->dim, other_coords)) {
13851398
if (op == Py_EQ) {
13861399
Py_RETURN_FALSE;
13871400
}
@@ -1394,10 +1407,6 @@ vector_richcompare(PyObject *o1, PyObject *o2, int op)
13941407
}
13951408
}
13961409

1397-
if (!PySequence_AsVectorCoords(other, other_coords, vec->dim)) {
1398-
return NULL;
1399-
}
1400-
14011410
switch (op) {
14021411
case Py_EQ:
14031412
for (i = 0; i < vec->dim; i++) {
@@ -1493,7 +1502,8 @@ static PyObject *
14931502
vector_dot(pgVector *self, PyObject *other)
14941503
{
14951504
double other_coords[VECTOR_MAX_SIZE];
1496-
if (!PySequence_AsVectorCoords(other, other_coords, self->dim)) {
1505+
if (!pg_VectorCoordsFromObjOldDontUseInNewCode(other, other_coords,
1506+
self->dim)) {
14971507
return RAISE(PyExc_TypeError,
14981508
"Cannot perform dot product with this type.");
14991509
}
@@ -1630,7 +1640,8 @@ vector_slerp(pgVector *self, PyObject *args)
16301640
if (!PyArg_ParseTuple(args, "Od:slerp", &other, &t)) {
16311641
return NULL;
16321642
}
1633-
if (!PySequence_AsVectorCoords(other, other_coords, self->dim)) {
1643+
if (!pg_VectorCoordsFromObjOldDontUseInNewCode(other, other_coords,
1644+
self->dim)) {
16341645
return RAISE(PyExc_TypeError, "Argument 1 must be a vector.");
16351646
}
16361647
if (fabs(t) > 1) {
@@ -1701,7 +1712,8 @@ vector_lerp(pgVector *self, PyObject *args)
17011712
if (!PyArg_ParseTuple(args, "Od:Vector.lerp", &other, &t)) {
17021713
return NULL;
17031714
}
1704-
if (!PySequence_AsVectorCoords(other, other_coords, self->dim)) {
1715+
if (!pg_VectorCoordsFromObjOldDontUseInNewCode(other, other_coords,
1716+
self->dim)) {
17051717
return RAISE(PyExc_TypeError, "Expected Vector as argument 1");
17061718
}
17071719
if (t < 0 || t > 1) {
@@ -1730,7 +1742,8 @@ vector_smoothstep(pgVector *self, PyObject *args)
17301742
if (!PyArg_ParseTuple(args, "Od:Vector.smoothstep", &other, &t)) {
17311743
return NULL;
17321744
}
1733-
if (!PySequence_AsVectorCoords(other, other_coords, self->dim)) {
1745+
if (!pg_VectorCoordsFromObjOldDontUseInNewCode(other, other_coords,
1746+
self->dim)) {
17341747
return RAISE(PyExc_TypeError, "Expected Vector as argument 1");
17351748
}
17361749

@@ -1765,7 +1778,7 @@ _vector_reflect_helper(double *dst_coords, const double *src_coords,
17651778
double norm_coords[VECTOR_MAX_SIZE];
17661779

17671780
/* normalize the normal */
1768-
if (!PySequence_AsVectorCoords(normal, norm_coords, dim)) {
1781+
if (!pg_VectorCoordsFromObjOldDontUseInNewCode(normal, norm_coords, dim)) {
17691782
return 0;
17701783
}
17711784

@@ -1992,7 +2005,8 @@ vector_project_onto(pgVector *self, PyObject *other)
19922005
double a_dot_b;
19932006
double b_dot_b;
19942007

1995-
if (!PySequence_AsVectorCoords(other, other_coords, self->dim)) {
2008+
if (!pg_VectorCoordsFromObjOldDontUseInNewCode(other, other_coords,
2009+
self->dim)) {
19962010
return RAISE(PyExc_TypeError, "Expected Vector as argument 1");
19972011
}
19982012

@@ -3795,12 +3809,8 @@ vector_elementwiseproxy_richcompare(PyObject *o1, PyObject *o2, int op)
37953809
}
37963810
dim = vec->dim;
37973811

3798-
if (pgVectorCompatible_Check(other, dim)) {
3799-
double other_coords[VECTOR_MAX_SIZE];
3800-
3801-
if (!PySequence_AsVectorCoords(other, other_coords, dim)) {
3802-
return NULL;
3803-
}
3812+
double other_coords[VECTOR_MAX_SIZE];
3813+
if (pg_VectorCoordsFromObj(other, dim, other_coords)) {
38043814
/* use diff == diff to check for NaN */
38053815
/* TODO: how should NaN be handled with LT/LE/GT/GE? */
38063816
switch (op) {
@@ -3955,11 +3965,8 @@ vector_elementwiseproxy_generic_math(PyObject *o1, PyObject *o2, int op)
39553965
other = (PyObject *)((vector_elementwiseproxy *)other)->vec;
39563966
}
39573967

3958-
if (pgVectorCompatible_Check(other, dim)) {
3968+
if (pg_VectorCoordsFromObj(other, dim, other_coords)) {
39593969
op |= OP_ARG_VECTOR;
3960-
if (!PySequence_AsVectorCoords(other, other_coords, dim)) {
3961-
return NULL;
3962-
}
39633970
}
39643971
else {
39653972
other_value = PyFloat_AsDouble(other);

0 commit comments

Comments
 (0)