Browse Source

fix array overrun in PfmFile.resize()

David Rose 6 years ago
parent
commit
210780f021

+ 5 - 4
panda/src/pnmimage/pnm-image-filter-core.cxx

@@ -43,8 +43,9 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source,
 
   WorkType *filter;
   float filter_width;
+  int actual_width;
 
-  make_filter(scale, width, filter, filter_width);
+  make_filter(scale, width, filter, filter_width, actual_width);
 
   for (b = 0; b < source.BSIZE(); b++) {
     for (a = 0; a < source.ASIZE(); a++) {
@@ -54,7 +55,7 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source,
     filter_row(temp_dest, dest.ASIZE(),
                temp_source, source.ASIZE(),
                scale,
-               filter, filter_width);
+               filter, filter_width, actual_width);
 
     for (a = 0; a < dest.ASIZE(); a++) {
       matrix[a][b] = temp_dest[a];
@@ -69,13 +70,13 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source,
   scale = (float)dest.BSIZE() / (float)source.BSIZE();
   temp_dest = (StoreType *)PANDA_MALLOC_ARRAY(dest.BSIZE() * sizeof(StoreType));
 
-  make_filter(scale, width, filter, filter_width);
+  make_filter(scale, width, filter, filter_width, actual_width);
 
   for (a = 0; a < dest.ASIZE(); a++) {
     filter_row(temp_dest, dest.BSIZE(),
                matrix[a], source.BSIZE(),
                scale,
-               filter, filter_width);
+               filter, filter_width, actual_width);
 
     for (b = 0; b < dest.BSIZE(); b++) {
       dest.SETVAL(a, b, channel, (float)temp_dest[b]/(float)source_max);

+ 10 - 5
panda/src/pnmimage/pnm-image-filter-sparse-core.cxx

@@ -49,10 +49,12 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source,
 
   WorkType *filter;
   float filter_width;
+  int actual_width;
 
-  make_filter(scale, width, filter, filter_width);
+  make_filter(scale, width, filter, filter_width, actual_width);
 
   for (b = 0; b < source.BSIZE(); b++) {
+    memset(temp_source, 0, source.ASIZE() * sizeof(StoreType));
     memset(temp_source_weight, 0, source.ASIZE() * sizeof(StoreType));
     for (a = 0; a < source.ASIZE(); a++) {
       if (source.HASVAL(a, b)) {
@@ -64,9 +66,10 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source,
     filter_sparse_row(temp_dest, temp_dest_weight, dest.ASIZE(),
                       temp_source, temp_source_weight, source.ASIZE(),
                       scale,
-                      filter, filter_width);
+                      filter, filter_width, actual_width);
 
     for (a = 0; a < dest.ASIZE(); a++) {
+      nassertv(!isnan(temp_dest[a]) && !isnan(temp_dest_weight[a]));
       matrix[a][b] = temp_dest[a];
       matrix_weight[a][b] = temp_dest_weight[a];
     }
@@ -83,17 +86,19 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source,
   temp_dest = (StoreType *)PANDA_MALLOC_ARRAY(dest.BSIZE() * sizeof(StoreType));
   temp_dest_weight = (StoreType *)PANDA_MALLOC_ARRAY(dest.BSIZE() * sizeof(StoreType));
 
-  make_filter(scale, width, filter, filter_width);
+  make_filter(scale, width, filter, filter_width, actual_width);
 
   for (a = 0; a < dest.ASIZE(); a++) {
     filter_sparse_row(temp_dest, temp_dest_weight, dest.BSIZE(),
                       matrix[a], matrix_weight[a], source.BSIZE(),
                       scale,
-                      filter, filter_width);
+                      filter, filter_width, actual_width);
 
     for (b = 0; b < dest.BSIZE(); b++) {
+      nassertv(!isnan(temp_dest[b]) && !isnan(temp_dest_weight[b]));
       if (temp_dest_weight[b] != 0) {
-        dest.SETVAL(a, b, channel, (float)temp_dest[b]/(float)source_max);
+        dest.SETVAL(a, b, channel, (float)temp_dest[b]/(float)temp_dest_weight[b]);
+        nassertv(!isnan(dest.GETVAL(a, b, channel)));
       }
     }
   }

+ 29 - 13
panda/src/pnmimage/pnm-image-filter.cxx

@@ -110,7 +110,8 @@ filter_row(StoreType dest[], int dest_len,
            const StoreType source[], int source_len,
            float scale,                    //  == dest_len / source_len
            const WorkType filter[],
-           float filter_width) {
+           float filter_width,
+           int actual_width) {
   // If we are expanding the row (scale > 1.0), we need to look at a
   // fractional granularity.  Hence, we scale our filter index by scale.  If
   // we are compressing (scale < 1.0), we don't need to fiddle with the filter
@@ -147,13 +148,15 @@ filter_row(StoreType dest[], int dest_len,
     // of center--so we don't have to incur the overhead of calling fabs()
     // each time through the loop.
     for (source_x = left; source_x < right_center; source_x++) {
-      index = (int)(iscale * (center - source_x) + 0.5f);
+      index = (int)cfloor(iscale * (center - source_x) + 0.5f);
+      nassertv(index >= 0 && index < actual_width);
       net_value += filter[index] * source[source_x];
       net_weight += filter[index];
     }
 
     for (; source_x <= right; source_x++) {
-      index = (int)(iscale * (source_x - center) + 0.5f);
+      index = (int)cfloor(iscale * (source_x - center) + 0.5f);
+      nassertv(index >= 0 && index < actual_width);
       net_value += filter[index] * source[source_x];
       net_weight += filter[index];
     }
@@ -174,15 +177,16 @@ filter_sparse_row(StoreType dest[], StoreType dest_weight[], int dest_len,
                   const StoreType source[], const StoreType source_weight[], int source_len,
                   float scale,                    //  == dest_len / source_len
                   const WorkType filter[],
-                  float filter_width) {
+                  float filter_width,
+                  int actual_width) {
   // If we are expanding the row (scale > 1.0), we need to look at a
   // fractional granularity.  Hence, we scale our filter index by scale.  If
   // we are compressing (scale < 1.0), we don't need to fiddle with the filter
   // index, so we leave it at one.
 
   float iscale;
-  if (scale < 1.0) {
-    iscale = 1.0;
+  if (scale < 1.0f) {
+    iscale = 1.0f;
     filter_width /= scale;
   } else {
     iscale = scale;
@@ -211,13 +215,15 @@ filter_sparse_row(StoreType dest[], StoreType dest_weight[], int dest_len,
     // of center--so we don't have to incur the overhead of calling fabs()
     // each time through the loop.
     for (source_x = left; source_x < right_center; source_x++) {
-      index = (int)(iscale * (center - source_x) + 0.5f);
+      index = (int)cfloor(iscale * (center - source_x) + 0.5f);
+      nassertv(index >= 0 && index < actual_width);
       net_value += filter[index] * source[source_x] * source_weight[source_x];
       net_weight += filter[index] * source_weight[source_x];
     }
 
     for (; source_x <= right; source_x++) {
-      index = (int)(iscale * (source_x - center) + 0.5f);
+      index = (int)cfloor(iscale * (source_x - center) + 0.5f);
+      nassertv(index >= 0 && index < actual_width);
       net_value += filter[index] * source[source_x] * source_weight[source_x];
       net_weight += filter[index] * source_weight[source_x];
     }
@@ -244,11 +250,12 @@ filter_sparse_row(StoreType dest[], StoreType dest_weight[], int dest_len,
 // corresponding to values in the range -filter_width to filter_width.
 
 typedef void FilterFunction(float scale, float width,
-                            WorkType *&filter, float &filter_width);
+                            WorkType *&filter, float &filter_width, int &actual_width);
 
 static void
 box_filter_impl(float scale, float width,
-                WorkType *&filter, float &filter_width) {
+                WorkType *&filter, float &filter_width,
+                int &actual_width) {
   float fscale;
   if (scale < 1.0) {
     // If we are compressing the image, we want to expand the range of the
@@ -263,7 +270,11 @@ box_filter_impl(float scale, float width,
     fscale = scale;
   }
   filter_width = width;
-  int actual_width = (int)cceil((filter_width + 1) * fscale) + 1;
+
+  // It seems we need a buffer of two extra values in the filter array
+  // to allow room for all calculations (especially including the 1/2
+  // pixel offset).
+  actual_width = (int)cceil((filter_width + 1) * fscale) + 2;
 
   filter = (WorkType *)PANDA_MALLOC_ARRAY(actual_width * sizeof(WorkType));
 
@@ -274,7 +285,8 @@ box_filter_impl(float scale, float width,
 
 static void
 gaussian_filter_impl(float scale, float width,
-                     WorkType *&filter, float &filter_width) {
+                     WorkType *&filter, float &filter_width,
+                     int &actual_width) {
   float fscale;
   if (scale < 1.0) {
     // If we are compressing the image, we want to expand the range of the
@@ -291,7 +303,11 @@ gaussian_filter_impl(float scale, float width,
 
   float sigma = width/2;
   filter_width = 3.0 * sigma;
-  int actual_width = (int)cceil((filter_width + 1) * fscale);
+
+  // It seems we need a buffer of two extra values in the filter array
+  // to allow room for all calculations (especially including the 1/2
+  // pixel offset).
+  actual_width = (int)cceil((filter_width + 1) * fscale) + 2;
 
   // G(x, y) = (1(2 pi sigma^2)) * exp( - (x^2 + y^2)  (2 sigma^2))