Fix: frozen mathutils Vector & Matrix types could be resized

It's important that frozen types are immutable, add a generic
check that mathutils types can be resized and check the frozen flag.

Also correct the exception types when Vector's cant be resized,
using a ValueError instead of a TypeError as the type is correct.
This commit is contained in:
Campbell Barton
2025-08-14 12:26:05 +10:00
parent 3198b336e1
commit 25c69382fc
5 changed files with 54 additions and 50 deletions

View File

@@ -612,6 +612,24 @@ void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self)
PyExc_TypeError, "%s is not frozen (mutable), call freeze first", Py_TYPE(self)->tp_name);
}
int _BaseMathObject_ResizeOkOrRaiseExc(BaseMathObject *self, const char *error_prefix)
{
if (UNLIKELY(self->flag & BASE_MATH_FLAG_IS_FROZEN)) {
PyErr_Format(PyExc_ValueError, "%s: cannot resize frozen data", error_prefix);
return -1;
}
if (UNLIKELY(self->flag & BASE_MATH_FLAG_IS_WRAP)) {
PyErr_Format(
PyExc_TypeError, "%s: cannot resize wrapped data - only Python vectors", error_prefix);
return -1;
}
if (UNLIKELY(self->cb_user)) {
PyErr_Format(PyExc_TypeError, "%s: cannot resize a vector that has an owner", error_prefix);
return -1;
}
return 0;
}
/* #BaseMathObject generic functions for all mathutils types. */
char BaseMathObject_owner_doc[] = "The item this is wrapping or None (read-only).";

View File

@@ -118,6 +118,9 @@ struct Mathutils_Callback {
[[nodiscard]] int _BaseMathObject_WriteCallback(BaseMathObject *self);
[[nodiscard]] int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index);
[[nodiscard]] int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
/** To implement #BaseMath_Prepare_ForResize. */
[[nodiscard]] int _BaseMathObject_ResizeOkOrRaiseExc(BaseMathObject *self,
const char *error_prefix);
void _BaseMathObject_RaiseFrozenExc(const BaseMathObject *self);
void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self);
@@ -154,6 +157,12 @@ void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self);
(UNLIKELY(((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) == 0) ? \
(_BaseMathObject_RaiseNotFrozenExc((BaseMathObject *)_self), -1) : \
0)
/**
* Helper to de-duplicate checks for in-place resizing.
* \return -1 and set an exception if the vector `_self` cannot be resized.
*/
#define BaseMathObject_Prepare_ForResize(_self, error_prefix) \
_BaseMathObject_ResizeOkOrRaiseExc((BaseMathObject *)_self, error_prefix)
/* utility func */
/**

View File

@@ -1391,16 +1391,8 @@ static PyObject *Matrix_resize_4x4(MatrixObject *self)
float mat[4][4];
int col;
if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_ValueError,
"Matrix.resize_4x4(): "
"cannot resize wrapped data - make a copy and resize that");
return nullptr;
}
if (self->cb_user) {
PyErr_SetString(PyExc_ValueError,
"Matrix.resize_4x4(): "
"cannot resize owned data - make a copy and resize that");
if (UNLIKELY(BaseMathObject_Prepare_ForResize(self, "Matrix.resize_4x4()") == -1)) {
/* An exception has been raised. */
return nullptr;
}

View File

@@ -497,16 +497,8 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value)
{
int vec_num;
if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize(): "
"cannot resize wrapped data - only Python vectors");
return nullptr;
}
if (self->cb_user) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize(): "
"cannot resize a vector that has an owner");
if (UNLIKELY(BaseMathObject_Prepare_ForResize(self, "Vector.resize()") == -1)) {
/* An exception has been raised. */
return nullptr;
}
@@ -585,16 +577,8 @@ PyDoc_STRVAR(
" Resize the vector to 2D (x, y).\n");
static PyObject *Vector_resize_2d(VectorObject *self)
{
if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_2d(): "
"cannot resize wrapped data - only Python vectors");
return nullptr;
}
if (self->cb_user) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_2d(): "
"cannot resize a vector that has an owner");
if (UNLIKELY(BaseMathObject_Prepare_ForResize(self, "Vector.resize_2d()") == -1)) {
/* An exception has been raised. */
return nullptr;
}
@@ -618,16 +602,8 @@ PyDoc_STRVAR(
" Resize the vector to 3D (x, y, z).\n");
static PyObject *Vector_resize_3d(VectorObject *self)
{
if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_3d(): "
"cannot resize wrapped data - only Python vectors");
return nullptr;
}
if (self->cb_user) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_3d(): "
"cannot resize a vector that has an owner");
if (UNLIKELY(BaseMathObject_Prepare_ForResize(self, "Vector.resize_3d()") == -1)) {
/* An exception has been raised. */
return nullptr;
}
@@ -655,16 +631,8 @@ PyDoc_STRVAR(
" Resize the vector to 4D (x, y, z, w).\n");
static PyObject *Vector_resize_4d(VectorObject *self)
{
if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_4d(): "
"cannot resize wrapped data - only Python vectors");
return nullptr;
}
if (self->cb_user) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_4d(): "
"cannot resize a vector that has an owner");
if (UNLIKELY(BaseMathObject_Prepare_ForResize(self, "Vector.resize_4d()") == -1)) {
/* An exception has been raised. */
return nullptr;
}