8000 Fix #5185: Be more careful about array dims · matplotlib/matplotlib@8394195 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8394195

Browse files
committed
Fix #5185: Be more careful about array dims
Check the dimensions on arrays passed to C++ to ensure they are what we expect.
1 parent c9351bd commit 8394195

File tree

5 files changed

+154
-51
lines changed

5 files changed

+154
-51
lines changed

src/_backend_agg.h

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -922,22 +922,6 @@ inline void RendererAgg::_draw_path_collection_generic(GCAgg &gc,
922922
typedef agg::conv_curve<snapped_t> snapped_curve_t;
923923
typedef agg::conv_curve<clipped_t> curve_t;
924924

925-
if (offsets.dim(0) != 0 && offsets.dim(1) != 2) {
926-
throw "Offsets array must be Nx2 or empty";
927-
}
928-
929-
if (facecolors.dim(0) != 0 && facecolors.dim(1) != 4) {
930-
throw "Facecolors array must be a Nx4 array or empty";
931-
}
932-
933-
if (edgecolors.dim(0) != 0 && edgecolors.dim(1) != 4) {
934-
throw "Edgecolors array must by Nx4 or empty";
935-
}
936-
937-
if (transforms.dim(0) != 0 && (transforms.dim(1) != 3 || transforms.dim(2) != 3)) {
938-
throw "Transforms array must by Nx3x3 or empty";
939-
}
940-
941925
size_t Npaths = path_generator.num_paths();
942926
size_t Noffsets = offsets.size();
943927
size_t N = std::max(Npaths, Noffsets);
@@ -1266,14 +1250,6 @@ inline void RendererAgg::draw_gouraud_triangle(GCAgg &gc,
12661250
set_clipbox(gc.cliprect, theRasterizer);
12671251
bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans);
12681252

1269-
if (points.dim(0) != 3 || points.dim(1) != 2) {
1270-
throw "points must be a 3x2 array";
1271-
}
1272-
1273-
if (colors.dim(0) != 3 || colors.dim(1) != 4) {
1274-
throw "colors must be a 3x4 array";
1275-
}
1276-
12771253
_draw_gouraud_triangle(points, colors, trans, has_clippath);
12781254
}
12791255

@@ -1288,18 +1264,6 @@ inline void RendererAgg::draw_gouraud_triangles(GCAgg &gc,
12881264
set_clipbox(gc.cliprect, theRasterizer);
12891265
bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans);
12901266

1291-
if (points.dim(1) != 3 || points.dim(2) != 2) {
1292-
throw "points must be a Nx3x2 array";
1293-
}
1294-
1295-
if (colors.dim(1) != 3 || colors.dim(2) != 4) {
1296-
throw "colors must be a Nx3x4 array";
1297-
}
1298-
1299-
if (points.dim(0) != colors.dim(0)) {
1300-
throw "points and colors arrays must be the same length";
1301-
}
1302-
13031267
for (int i = 0; i < points.dim(0); ++i) {
13041268
typename PointArray::sub_t point = points[i];
13051269
typename ColorArray::sub_t color = colors[i];

src/_backend_agg_wrapper.cpp

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -340,15 +340,15 @@ PyRendererAgg_draw_path_collection(PyRendererAgg *self, PyObject *args, PyObject
340340
&convert_trans_affine,
341341
&master_transform,
342342
&pathobj,
343-
&transforms.converter,
343+
&convert_transforms,
344344
&transforms,
345-
&offsets.converter,
345+
&convert_points,
346346
&offsets,
347347
&convert_trans_affine,
348348
&offset_trans,
349-
&facecolors.converter,
349+
&convert_colors,
350350
&facecolors,
351-
&edgecolors.converter,
351+
&convert_colors,
352352
&edgecolors,
353353
&linewidths.converter,
354354
&linewidths,
@@ -411,14 +411,14 @@ static PyObject *PyRendererAgg_draw_quad_mesh(PyRendererAgg *self, PyObject *arg
411411
&mesh_height,
412412
&coordinates.converter,
413413
&coordinates,
414-
&offsets.converter,
414+
&convert_points,
415415
&offsets,
416416
&convert_trans_affine,
417417
&offset_trans,
418-
&facecolors.converter,
418+
&convert_colors,
419419
&facecolors,
420420
&antialiased,
421-
&edgecolors.converter,
421+
&convert_colors,
422422
&edgecolors)) {
423423
return NULL;
424424
}
@@ -459,6 +459,21 @@ PyRendererAgg_draw_gouraud_triangle(PyRendererAgg *self, PyObject *args, PyObjec
459459
return NULL;
460460
}
461461

462+
if (points.dim(0) != 3 || points.dim(1) != 2) {
463+
PyErr_Format(PyExc_ValueError,
464+
"points must be a 3x2 array, got %dx%d",
465+
points.dim(0), points.dim(1));
466+
return NULL;
467+
}
468+
469+
if (colors.dim(0) != 3 || colors.dim(1) != 4) {
470+
PyErr_Format(PyExc_ValueError,
471+
"colors must be a 3x4 array, got %dx%d",
472+
colors.dim(0), colors.dim(1));
473+
return NULL;
474+
}
475+
476+
462477
CALL_CPP("draw_gouraud_triangle", (self->x->draw_gouraud_triangle(gc, points, colors, trans)));
463478

464479
Py_RETURN_NONE;
@@ -485,6 +500,27 @@ PyRendererAgg_draw_gouraud_triangles(PyRendererAgg *self, PyObject *args, PyObje
485500
return NULL;
486501
}
487502

503+
if (points.dim(1) != 3 || points.dim(2) != 2) {
504+
PyErr_Format(PyExc_ValueError,
505+
"points must be a Nx3x2 array, got %dx%dx%d",
506+
points.dim(0), points.dim(1), points.dim(2));
507+
return NULL;
508+
}
509+
510+
if (colors.dim(1) != 3 || colors.dim(2) != 4) {
511+
PyErr_Format(PyExc_ValueError,
512+
"colors must be a Nx3x4 array, got %dx%dx%d",
513+
colors.dim(0), colors.dim(1), colors.dim(2));
514+
return NULL;
515+
}
516+
517+
if (points.dim(0) != colors.dim(0)) {
518+
PyErr_Format(PyExc_ValueError,
519+
"points and colors arrays must be the same length, got %d and %d",
520+
points.dim(0), colors.dim(0));
521+
return NULL;
522+
}
523+
488524
CALL_CPP("draw_gouraud_triangles", self->x->draw_gouraud_triangles(gc, points, colors, trans));
489525

490526
Py_RETURN_NONE;

src/_path_wrapper.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ static PyObject *Py_points_in_path(PyObject *self, PyObject *args, PyObject *kwd
6969

7070
if (!PyArg_ParseTuple(args,
7171
"O&dO&O&:points_in_path",
72-
&points.converter,
72+
&convert_points,
7373
&points,
7474
&r,
7575
&convert_path,
@@ -128,7 +128,7 @@ static PyObject *Py_points_on_path(PyObject *self, PyObject *args, PyObject *kwd
128128

129129
if (!PyArg_ParseTuple(args,
130130
"O&dO&O&:points_on_path",
131-
&points.converter,
131+
&convert_points,
132132
&points,
133133
&r,
134134
&convert_path,
@@ -200,7 +200,10 @@ static PyObject *Py_update_path_extents(PyObject *self, PyObject *args, PyObject
200200
}
201201

202202
if (minpos.dim(0) != 2) {
203-
PyErr_SetString(PyExc_ValueError, "minpos must be of length 2");
203+
PyErr_Format(PyExc_ValueError,
204+
"minpos must be of length 2, got %d",
205+
minpos.dim(0));
206+
return NULL;
204207
}
205208

206209
extent_limits e;
@@ -263,9 +266,9 @@ static PyObject *Py_get_path_collection_extents(PyObject *self, PyObject *args,
263266
&convert_trans_affine,
264267
&master_transform,
265268
&pathsobj,
266-
&transforms.converter,
269+
&convert_transforms,
267270
&transforms,
268-
&offsets.converter,
271+
&convert_points,
269272
&offsets,
270273
&convert_trans_affine,
271274
&offset_trans)) {
@@ -319,9 +322,9 @@ static PyObject *Py_point_in_path_collection(PyObject *self, PyObject *args, PyO
319322
&convert_trans_affine,
320323
&master_transform,
321324
&pathsobj,
322-
&transforms.converter,
325+
&convert_transforms,
323326
&transforms,
324-
&offsets.converter,
327+
&convert_points,
325328
&offsets,
326329
&convert_trans_affine,
327330
&offset_trans,
@@ -464,7 +467,7 @@ static PyObject *Py_count_bboxes_overlapping_bbox(PyObject *self, PyObject *args
464467
"O&O&:count_bboxes_overlapping_bbox",
465468
&convert_rect,
466469
&bbox,
467-
&bboxes.converter,
470+
&convert_bboxes,
468471
&bboxes)) {
469472
return NULL;
470473
}

src/py_converters.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,4 +518,100 @@ int convert_face(PyObject *color, GCAgg &gc, agg::rgba *rgba)
518518

519519
return 1;
520520
}
521+
522+
int convert_points(PyObject *obj, void *pointsp)
523+
{
524+
numpy::array_view<double, 2> *points = (numpy::array_view<double, 2> *)pointsp;
525+
526+
if (obj == NULL || obj == Py_None) {
527+
return 1;
528+
}
529+
530+
points->set(obj);
531+
532+
if (points->dim(0) == 0) {
533+
return 1;
534+
}
535+
536+
if (points->dim(1) != 2) {
537+
PyErr_Format(PyExc_ValueError,
538+
"Points must be Nx2 array, got %dx%d",
539+
points->dim(0), points->dim(1));
540+
return 0;
541+
}
542+
543+
return 1;
544+
}
545+
546+
int convert_transforms(PyObject *obj, void *transp)
547+
{
548+
numpy::array_view<double, 3> *trans = (numpy::array_view<double, 3> *)transp;
549+
550+
if (obj == NULL || obj == Py_None) {
551+
return 1;
552+
}
553+
554+
trans->set(obj);
555+
556+
if (trans->dim(0) == 0) {
557+
return 1;
558+
}
559+
560+
if (trans->dim(1) != 3 || trans->dim(2) != 3) {
561+
PyErr_Format(PyExc_ValueError,
562+
"Transforms must be Nx3x3 array, got %dx%dx%d",
563+
trans->dim(0), trans->dim(1), trans->dim(2));
564+
return 0;
565+
}
566+
567+
return 1;
568+
}
569+
570+
int convert_bboxes(PyObject *obj, void *bboxp)
571+
{
572+
numpy::array_view<double, 3> *bbox = (numpy::array_view<double, 3> *)bboxp;
573+
574+
if (obj == NULL || obj == Py_None) {
575+
return 1;
576+
}
577+
578+
bbox->set(obj);
579+
580+
if (bbox->dim(0) == 0) {
581+
return 1;
582+
}
583+
584+
if (bbox->dim(1) != 2 || bbox->dim(2) != 2) {
585+
PyErr_Format(PyExc_ValueError,
586+
"Bbox array must be Nx2x2 array, got %dx%dx%d",
587+
bbox->dim(0), bbox->dim(1), bbox->dim(2));
588+
return 0;
589+
}
590+
591+
return 1;
592+
}
593+
594+
int convert_colors(PyObject *obj, void *colorsp)
595+
{
596+
numpy::array_view<double, 2> *colors = (numpy::array_view<double, 2> *)colorsp;
597+
598+
if (obj == NULL || obj == Py_None) {
599+
return 1;
600+
}
601+
602+
colors->set(obj);
603+
604+
if (colors->dim(0) == 0) {
605+
return 1;
606+
}
607+
608+
if (colors->dim(1) != 4) {
609+
PyErr_Format(PyExc_ValueError,
610+
"Colors array must be Nx4 array, got %dx%d",
611+
colors->dim(0), colors->dim(1));
612+
return 0;
613+
}
614+
615+
return 1;
616+
}
521617
}

src/py_converters.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ int convert_snap(PyObject *obj, void *snapp);
3838
int convert_offset_position(PyObject *obj, void *offsetp);
3939
int convert_sketch_params(PyObject *obj, void *sketchp);
4040
int convert_gcagg(PyObject *pygc, void *gcp);
41+
int convert_points(PyObject *pygc, void *pointsp);
42+
int convert_transforms(PyObject *pygc, void *transp);
43+
int convert_bboxes(PyObject *pygc, void *bboxp);
44+
int convert_colors(PyObject *pygc, void *colorsp);
4145

4246
int convert_face(PyObject *color, GCAgg &gc, agg::rgba *rgba);
4347
}

0 commit comments

Comments
 (0)
0