|
From: Steven G. J. <st...@gi...> - 2000-08-24 03:23:09
|
Hi, I've encountered a problem with the Vis5d 5.2 code: the contour()
plotting function declares very large arrays (2.5 MB!) on the stack.
This causes the stack space to be exhausted sometimes (under Linux),
resulting in crashes. (Thanks to Tairan Wang at MIT for finding this
bug.)
The below patch modifies contour() to allocate these arrays dynamically
with malloc(); there shouldn't be much speed hit since calc_{hv}slice
already allocates 6 or more such arrays with malloc() anyway.
As long as I was allocating them dynamically, I thought I'd allocate a
buffer just big enough to hold the maximum possible number of vertices for
the given slice, rather than a fixed 400*400 array. Looking through the
contour() source code, it seems that the maximum possible number of
vertices for the most pathological slice is:
4*(nrows-1)*(ncols-1)*|(high-low)/interval|
I'd appreciate it if someone took a look at contour.c and checked this
(Bill?). (It works fine on for the sample cases I've tried, checking for
array overruns with Electric Fence.) In any case, the old code already
had checks for overruns, so the worst that can happen is that the
contour-drawing stops partway through the slice.
I hope that this patch, or something like it, goes into the main Vis5d
sources. I'll be releasing a 1.0.1 update to Vis5d+ soon
(vis5d.sourceforge.net).
Steven
PS. With this fix and my earlier modifications to Vis5d+ (e.g. adding
POSIX mutex support), I believe that POSIX threading now works under
Linux.
Index: contour.c
===================================================================
RCS file: /cvsroot/vis5d/vis5d/src/contour.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 contour.c
--- contour.c 2000/08/05 19:26:55 1.1.1.1
+++ contour.c 2000/08/24 02:06:01
@@ -37,7 +37,7 @@
#define XY
-
+#include <stdio.h>
#include <string.h>
#include "memory.h"
#include "globals.h"
@@ -669,8 +669,8 @@
float xd, yd ,xx, yy;
float clow, chi;
float gg;
- float vx[MAXTEMP], vy[MAXTEMP];
- int ipnt[2*MAXTEMP];
+ float *vx, *vy;
+ int *ipnt;
int nump, ip;
register int numv;
char *mark;
@@ -680,6 +680,22 @@
int lbl_len, lbl_dot;
int use_resize;
+ /* Dynamically allocate temp. arrays, to avoid using excessive
+ stack space and crashing on some systems. It's not going to be
+ appreciably slower, since the caller (calc_hslice or
+ calc_vslice) calls malloc at least 6 times anyway. calc_hslice
+ and calc_vslice determine maxv1 & maxv2 based on an upper bound
+ for the number of vertices derived from the code below. */
+ const int maxtemp = maxv1 > maxv2 ? maxv1 : maxv2;
+ vx = (float*) malloc(sizeof(float)*maxtemp);
+ vy = (float*) malloc(sizeof(float)*maxtemp);
+ ipnt = (int*) malloc(sizeof(int)*((nr-1)*(nc-1) + 1)); /* see below loop */
+ if (!vx || !vy || !ipnt) {
+ fprintf(stderr, "You do not have enough memory to create contours.\n");
+ free(vx); free(vy); free(ipnt);
+ return 0;
+ }
+
use_resize = 0;
ffex = ffey = 0;
@@ -697,6 +713,7 @@
if (interval==0.0) {
/* bad contour interval */
+ free(vx); free(vy); free(ipnt);
return 0;
}
if (interval<0.0) {
@@ -764,8 +781,10 @@
/* allocate mark array */
mark = (char *) allocate( ctx, nr * nc * sizeof(char) );
- if (!mark)
+ if (!mark) {
+ free(vx); free(vy); free(ipnt);
return 0;
+ }
/* initialize mark array to zeros */
memset( mark, 0, nr*nc*sizeof(char) );
@@ -806,9 +825,9 @@
numv = nump = 0;
/* compute contours */
- for (ir=0; ir<nrm && numv<MAXTEMP-8 && nump<2*MAXTEMP; ir++) {
+ for (ir=0; ir<nrm && numv<maxtemp-8 && nump<2*maxtemp; ir++) {
xx = xd*ir+XMIN;
- for (ic=0; ic<ncm && numv<MAXTEMP-8 && nump<2*MAXTEMP; ic++) {
+ for (ic=0; ic<ncm && numv<maxtemp-8 && nump<2*maxtemp; ic++) {
float ga, gb, gc, gd;
float gv, gn, gx;
register float tmp1, tmp2;
@@ -870,7 +889,7 @@
/* gg is current contour line value */
gg = clow;
- for (il=0; il<numc && numv+8<MAXTEMP; il++, gg += interval) {
+ for (il=0; il<numc && numv+8<maxtemp; il++, gg += interval) {
float gba, gca, gdb, gdc;
int ii;
@@ -1151,8 +1170,8 @@
/* copy vertices from vx, vy arrays to either v1 or v2 arrays */
ip = 0;
- for (ir=0;ir<nrm && ip<2*MAXTEMP;ir++) {
- for (ic=0;ic<ncm && ip<2*MAXTEMP;ic++) {
+ for (ir=0;ir<nrm && ip<2*maxtemp;ir++) {
+ for (ic=0;ic<ncm && ip<2*maxtemp;ic++) {
int start, len;
start = ipnt[ip];
len = ipnt[ip+1] - start;
@@ -1179,6 +1198,8 @@
/* deallocate mark array */
deallocate( ctx, mark, nr * nc * sizeof(char) );
+
+ free(vx); free(vy); free(ipnt);
return 1;
}
Index: work.c
===================================================================
RCS file: /cvsroot/vis5d/vis5d/src/work.c,v
retrieving revision 1.3
diff -u -r1.3 work.c
--- work.c 2000/08/06 07:07:27 1.3
+++ work.c 2000/08/24 02:06:02
@@ -1922,6 +1922,8 @@
float *boxverts;
int numboxverts;
Display_Context dtx;
+ int contour_ok;
+ int max_cont_verts;
dtx = ctx->dpy_ctx;
/* MJK 12.04.98 */
@@ -1993,13 +1995,20 @@
if (!slicedata)
return;
- vr1 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS);
- vc1 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS);
- vr2 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
- vc2 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
- vr3 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
- vc3 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
- vl = (float *) malloc(sizeof(float)*MAX_CONT_VERTS);
+ /* compute an upper bound on the number of vertices that contour()
+ can return: */
+ max_cont_verts = 4 * (dtx->Nr-1) * (dtx->Nc-1)
+ * fabs((high-low)/interval) + .5;
+ if (max_cont_verts > MAX_CONT_VERTS)
+ max_cont_verts = MAX_CONT_VERTS;
+
+ vr1 = (float *) malloc(sizeof(float)*max_cont_verts);
+ vc1 = (float *) malloc(sizeof(float)*max_cont_verts);
+ vr2 = (float *) malloc(sizeof(float)*max_cont_verts/2);
+ vc2 = (float *) malloc(sizeof(float)*max_cont_verts/2);
+ vr3 = (float *) malloc(sizeof(float)*max_cont_verts/2);
+ vc3 = (float *) malloc(sizeof(float)*max_cont_verts/2);
+ vl = (float *) malloc(sizeof(float)*max_cont_verts);
if (!vr1 || !vc1 || !vr2 || !vc2 || !vr3 || !vc3 || !vl){
printf(" You do not have enough memory to create hslices.\n");
@@ -2013,7 +2022,7 @@
free(vr2);
}
if (vc2){
- free(vr3);
+ free(vc2);
}
if (vc3){
free(vc3);
@@ -2035,16 +2044,21 @@
base = low;
/* call contouring routine */
- contour( ctx, slicedata, dtx->Nr, dtx->Nc, interval, low, high, base,
- vr1, vc1, MAX_CONT_VERTS, &num1,
- vr2, vc2, MAX_CONT_VERTS/2, &num2,
- vr3, vc3, MAX_CONT_VERTS/2, &num3
- );
+ contour_ok =
+ contour( ctx, slicedata, dtx->Nr, dtx->Nc, interval, low, high, base,
+ vr1, vc1, max_cont_verts, &num1,
+ vr2, vc2, max_cont_verts/2, &num2,
+ vr3, vc3, max_cont_verts/2, &num3);
/* done with grid and slice */
deallocate( ctx, slicedata, -1 );
release_grid( ctx, time, var, grid );
+ if (!contour_ok) {
+ free(vr1);free(vc1);free(vr2);free(vc2);free(vr3);free(vc3);free(vl);
+ return;
+ }
+
/* generate level coordinates array */
if (num1>num2 && num1>num3) {
maxnum = num1;
@@ -2067,7 +2081,7 @@
/* MJK 12.04.98 */
if (ctx->DisplaySfcHSlice[var]){
- num1 = fit_vecs_to_topo (ctx, num1, MAX_CONT_VERTS, vr1, vc1, vl);
+ num1 = fit_vecs_to_topo (ctx, num1, max_cont_verts, vr1, vc1, vl);
}
@@ -2087,7 +2101,7 @@
/* MJK 12.04.98 */
if (ctx->DisplaySfcHSlice[var]){
- num2 = fit_vecs_to_topo (ctx, num2, MAX_CONT_VERTS/2, vr2, vc2, vl);
+ num2 = fit_vecs_to_topo (ctx, num2, max_cont_verts/2, vr2, vc2, vl);
}
@@ -2107,7 +2121,7 @@
/* MJK 12.04.98 */
if (ctx->DisplaySfcHSlice[var]){
- num3 = fit_vecs_to_topo (ctx, num3, MAX_CONT_VERTS/2, vr3, vc3, vl);
+ num3 = fit_vecs_to_topo (ctx, num3, max_cont_verts/2, vr3, vc3, vl);
}
@@ -2204,6 +2218,8 @@
int numboxverts;
Display_Context dtx;
int ctxnl, ctxll;
+ int contour_ok;
+ int max_cont_verts;
/* WLH 15 Oct 98 */
float ctxlow;
@@ -2232,15 +2248,21 @@
if (!slice)
return;
- vr1 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS);
- vc1 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS);
- vl1 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS);
- vr2 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
- vc2 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
- vl2 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
- vr3 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
- vc3 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
- vl3 = (float *) malloc(sizeof(float)*MAX_CONT_VERTS/2);
+ /* compute an upper bound on the number of vertices that contour()
+ can return: */
+ max_cont_verts = 4 * (rows-1) * (cols-1) * fabs((high-low)/interval) + .5;
+ if (max_cont_verts > MAX_CONT_VERTS)
+ max_cont_verts = MAX_CONT_VERTS;
+
+ vr1 = (float *) malloc(sizeof(float)*max_cont_verts);
+ vc1 = (float *) malloc(sizeof(float)*max_cont_verts);
+ vl1 = (float *) malloc(sizeof(float)*max_cont_verts);
+ vr2 = (float *) malloc(sizeof(float)*max_cont_verts/2);
+ vc2 = (float *) malloc(sizeof(float)*max_cont_verts/2);
+ vl2 = (float *) malloc(sizeof(float)*max_cont_verts/2);
+ vr3 = (float *) malloc(sizeof(float)*max_cont_verts/2);
+ vc3 = (float *) malloc(sizeof(float)*max_cont_verts/2);
+ vl3 = (float *) malloc(sizeof(float)*max_cont_verts/2);
if (!vr1 || !vc1 || !vl1 || !vr2 || !vc2 || !vl2 || !vr3 || !vc3 || !vl3){
printf(" You do not have enough memory to create vslices.\n");
if (vr1){
@@ -2281,14 +2303,20 @@
else
base = low;
/* call contouring routine */
- contour( ctx, slice, rows, cols, interval, low, high, base,
- vr1, vc1, MAX_CONT_VERTS, &num1,
- vr2, vc2, MAX_CONT_VERTS/2, &num2,
- vr3, vc3, MAX_CONT_VERTS/2, &num3
- );
+ contour_ok =
+ contour( ctx, slice, rows, cols, interval, low, high, base,
+ vr1, vc1, max_cont_verts, &num1,
+ vr2, vc2, max_cont_verts/2, &num2,
+ vr3, vc3, max_cont_verts/2, &num3);
deallocate( ctx, slice, -1 );
release_grid( ctx, time, var, grid );
+
+ if (!contour_ok) {
+ free(vr1); free(vc1); free(vr2); free(vc2); free(vr3); free(vc3);
+ free(vl1); free(vl2); free(vl3);
+ return;
+ }
/*
* Convert 2-D coordinates from [0,rows-1][0,cols-1] to 3-D coords
|