src/output/cairo-chart.h (xrchart_write_scale): Check the range and deal with the...
authorJohn Darrington <john@darrington.wattle.id.au>
Sat, 11 Jul 2020 07:35:29 +0000 (09:35 +0200)
committerJohn Darrington <john@darrington.wattle.id.au>
Sat, 11 Jul 2020 07:45:14 +0000 (09:45 +0200)
If a chart was requested where either scale had an range of zero
(the minimum value and the maximum value were equal), then all
sorts of memory errors could occur later in the chart's rendering.

This change checks for this condition early and refuses to draw the
chart in this case.

src/output/cairo-chart.c
src/output/cairo-chart.h
src/output/charts/barchart-cairo.c
src/output/charts/boxplot-cairo.c
src/output/charts/np-plot-cairo.c
src/output/charts/plot-hist-cairo.c
src/output/charts/roc-chart-cairo.c
src/output/charts/scatterplot-cairo.c
src/output/charts/scree-cairo.c
src/output/charts/spreadlevel-cairo.c

index c5bffcd761c891597ec2f2b462eb9b4cac36dbbd..00eb98f5f91b0915ad6c129934c3e16e6dfaef25 100644 (file)
@@ -1,5 +1,6 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009, 2010, 2011, 2014, 2015 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009, 2010, 2011, 2014, 2015,
+   2020 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -365,7 +366,7 @@ xrchart_text_extents (cairo_t *cr, const struct xrchart_geometry *geom,
   pango_font_description_free (desc);
 }
 
-static void
+static bool
 xrchart_write_scale (cairo_t *cr, struct xrchart_geometry *geom,
                     double smin, double smax, enum tick_orientation orient)
 {
@@ -379,6 +380,9 @@ xrchart_write_scale (cairo_t *cr, struct xrchart_geometry *geom,
   char *tick_format_string;
   bool tickoversize = false;
 
+  if (smax == smin)
+    return false;
+
   chart_get_scale (smax, smin, &lower, &interval, &ticks);
 
   tick_format_string = chart_get_ticks_format (lower, interval, ticks, &tickscale);
@@ -417,22 +421,24 @@ xrchart_write_scale (cairo_t *cr, struct xrchart_geometry *geom,
       pos += interval;
     }
   free(tick_format_string);
+
+  return true;
 }
 
 /* Set the scale for the ordinate */
-void
+bool
 xrchart_write_yscale (cairo_t *cr, struct xrchart_geometry *geom,
                     double smin, double smax)
 {
-  xrchart_write_scale (cr, geom, smin, smax, SCALE_ORDINATE);
+  return xrchart_write_scale (cr, geom, smin, smax, SCALE_ORDINATE);
 }
 
 /* Set the scale for the abscissa */
-void
+bool
 xrchart_write_xscale (cairo_t *cr, struct xrchart_geometry *geom,
                      double smin, double smax)
 {
-  xrchart_write_scale (cr, geom, smin, smax, SCALE_ABSCISSA);
+  return xrchart_write_scale (cr, geom, smin, smax, SCALE_ABSCISSA);
 }
 
 
index 60ef282928b913e768ca25c693793abdfe9ef9bd..68f2978283b93edc63c3507ca05b2d970c3de0bc 100644 (file)
@@ -117,13 +117,12 @@ void xrchart_write_title (cairo_t *, const struct xrchart_geometry *,
   PRINTF_FORMAT (3, 4);
 
 /* Set the scale for the abscissa */
-void xrchart_write_xscale (cairo_t *, struct xrchart_geometry *,
-                           double min, double max);
-
+bool xrchart_write_xscale (cairo_t *, struct xrchart_geometry *,
+                           double min, double max) WARN_UNUSED_RESULT;
 
 /* Set the scale for the ordinate */
-void xrchart_write_yscale (cairo_t *, struct xrchart_geometry *,
-                           double smin, double smax);
+bool xrchart_write_yscale (cairo_t *, struct xrchart_geometry *,
+                           double smin, double smax) WARN_UNUSED_RESULT;
 
 void xrchart_write_xlabel (cairo_t *, const struct xrchart_geometry *,
                            const char *label) ;
index e6f33ad118b3087ebfdd91b7ae23304e1d24e76c..00b33fc6b0f182b5fa7f92b6dd97c3e0d5f6af5a 100644 (file)
@@ -67,10 +67,9 @@ xrchart_draw_barchart (const struct chart_item *chart_item, cairo_t *cr,
   xrchart_write_ylabel (cr, geom, bc->ylabel);
   xrchart_write_xlabel (cr, geom, chart_item_get_title (chart_item));
 
-  if (bc->percent)
-    xrchart_write_yscale (cr, geom, 0, bc->largest * 100.0 / bc->total_count);
-  else
-    xrchart_write_yscale (cr, geom, 0, bc->largest);
+  if (! xrchart_write_yscale (cr, geom, 0,
+                              bc->percent ? bc->largest * 100.0 / bc->total_count : bc->largest))
+    return;
 
   const double abscale = geom->axis[SCALE_ABSCISSA].data_max - geom->axis[SCALE_ABSCISSA].data_min;
   const double width = abscale / (double) (bc->n_nzcats + bc->n_pcats);
index 041b4fabb8decb597bec804a7e6bcf83497a7d0c..b79b45f5e8e57721c59179b772cdcfd525e7c748 100644 (file)
@@ -152,7 +152,9 @@ xrchart_draw_boxplot (const struct chart_item *chart_item, cairo_t *cr,
   double box_width;
   size_t i;
 
-  xrchart_write_yscale (cr, geom, boxplot->y_min, boxplot->y_max);
+  if (! xrchart_write_yscale (cr, geom, boxplot->y_min, boxplot->y_max))
+    return;
+
   xrchart_write_title (cr, geom, "%s", chart_item->title);
 
   box_width = (geom->axis[SCALE_ABSCISSA].data_max - geom->axis[SCALE_ABSCISSA].data_min) / boxplot->n_boxes / 2.0;
index e9a1e07033fbf02296458fd8c69ab90004d8aaa6..aa7d6773481a24b40f00cfec396ad669d34675e7 100644 (file)
@@ -37,10 +37,13 @@ np_plot_chart_draw (const struct chart_item *chart_item, cairo_t *cr,
   xrchart_write_title (cr, geom, _("Normal Q-Q Plot of %s"), chart_item->title);
   xrchart_write_xlabel (cr, geom, _("Observed Value"));
   xrchart_write_ylabel (cr, geom, _("Expected Normal"));
-  xrchart_write_xscale (cr, geom,
+  if (! xrchart_write_xscale (cr, geom,
                       npp->x_lower - npp->slack,
-                      npp->x_upper + npp->slack);
-  xrchart_write_yscale (cr, geom, npp->y_first, npp->y_last);
+                              npp->x_upper + npp->slack))
+    return;
+
+  if (! xrchart_write_yscale (cr, geom, npp->y_first, npp->y_last))
+    return;
 
   data = casereader_clone (npp->data);
   for (; (c = casereader_read (data)) != NULL; case_unref (c))
@@ -64,8 +67,10 @@ dnp_plot_chart_draw (const struct chart_item *chart_item, cairo_t *cr,
   xrchart_write_title (cr, geom, _("Detrended Normal Q-Q Plot of %s"), chart_item->title);
   xrchart_write_xlabel (cr, geom, _("Observed Value"));
   xrchart_write_ylabel (cr, geom, _("Dev from Normal"));
-  xrchart_write_xscale (cr, geom, dnpp->y_min, dnpp->y_max);
-  xrchart_write_yscale (cr, geom, dnpp->dns_min, dnpp->dns_max);
+  if (! xrchart_write_xscale (cr, geom, dnpp->y_min, dnpp->y_max))
+    return;
+  if (! xrchart_write_yscale (cr, geom, dnpp->dns_min, dnpp->dns_max))
+    return;
 
   data = casereader_clone (dnpp->data);
   for (; (c = casereader_read (data)) != NULL; case_unref (c))
index 000695f331abdcded8c3e7097048b4305d6c6479..620fe68c23fb460d70395b7bfbdc8d8abfd0e179 100644 (file)
@@ -118,9 +118,11 @@ xrchart_draw_histogram (const struct chart_item *chart_item, cairo_t *cr,
       return;
     }
 
-  xrchart_write_yscale (cr, geom, 0, gsl_histogram_max_val (h->gsl_hist));
-  xrchart_write_xscale (cr, geom, gsl_histogram_min (h->gsl_hist),
-                       gsl_histogram_max (h->gsl_hist));
+  if (! xrchart_write_yscale (cr, geom, 0, gsl_histogram_max_val (h->gsl_hist)))
+    return;
+  if (! xrchart_write_xscale (cr, geom, gsl_histogram_min (h->gsl_hist),
+                              gsl_histogram_max (h->gsl_hist)))
+    return;
 
 
   /* Draw the ticks and compute if the rendered tick text is wider than the bin */
index 97f7a45d9ad6293755ba5d401fdae386af2d955f..ae2db62efbd6f7acd4482be82323d70bc093e154 100644 (file)
@@ -37,8 +37,10 @@ xrchart_draw_roc (const struct chart_item *chart_item, cairo_t *cr,
   xrchart_write_xlabel (cr, geom, _("1 - Specificity"));
   xrchart_write_ylabel (cr, geom, _("Sensitivity"));
 
-  xrchart_write_xscale (cr, geom, 0, 1);
-  xrchart_write_yscale (cr, geom, 0, 1);
+  if (! xrchart_write_xscale (cr, geom, 0, 1))
+    return;
+  if (! xrchart_write_yscale (cr, geom, 0, 1))
+    return;
 
   if (rc->reference)
     {
index 86e54c6e5abc1ea826364d571270d81219450054..cf62539fab1d5b29e2b65e11a225f2b9bbfba9ed 100644 (file)
@@ -50,8 +50,10 @@ xrchart_draw_scatterplot (const struct chart_item *chart_item, cairo_t *cr,
   if (spc->byvar)
     byvar_width = var_get_width (spc->byvar);
 
-  xrchart_write_xscale (cr, geom, spc->x_min, spc->x_max);
-  xrchart_write_yscale (cr, geom, spc->y_min, spc->y_max);
+  if (! xrchart_write_xscale (cr, geom, spc->x_min, spc->x_max))
+    return;
+  if (! xrchart_write_yscale (cr, geom, spc->y_min, spc->y_max))
+    return;
   xrchart_write_title (cr, geom, _("Scatterplot %s"), chart_item->title);
   xrchart_write_xlabel (cr, geom, spc->xlabel);
   xrchart_write_ylabel (cr, geom, spc->ylabel);
index a3ae10cd6287e5ecf384485b69f3c21d66985fd3..d203b62eff4d983c2f5f5ceada6052d53f3c1331 100644 (file)
@@ -44,8 +44,10 @@ xrchart_draw_scree (const struct chart_item *chart_item, cairo_t *cr,
   else
     max = fabs (min);
 
-  xrchart_write_yscale (cr, geom, 0, max);
-  xrchart_write_xscale (cr, geom, 0, rc->eval->size + 1);
+  if (! xrchart_write_yscale (cr, geom, 0, max))
+    return;
+  if (! xrchart_write_xscale (cr, geom, 0, rc->eval->size + 1))
+    return;
 
   xrchart_vector_start (cr, geom, "");
   for (i = 0 ; i < rc->eval->size; ++i)
index 389a487b01599953c04e1842e4fe03047ca46eac..7167c4c8e6cf57e8dd74f14a5d82b52910318354 100644 (file)
@@ -39,8 +39,11 @@ xrchart_draw_spreadlevel (const struct chart_item *chart_item, cairo_t *cr,
   xrchart_write_ylabel (cr, geom, _("Spread"));
 
 
-  xrchart_write_xscale (cr, geom, sl->x_lower, sl->x_upper);
-  xrchart_write_yscale (cr, geom, sl->y_lower, sl->y_upper);
+  if (! xrchart_write_xscale (cr, geom, sl->x_lower, sl->x_upper))
+    return;
+
+  if (! xrchart_write_yscale (cr, geom, sl->y_lower, sl->y_upper))
+    return;
 
   for (i = 0 ; i < sl->n_data; ++i)
     {