Evas masking: Avoid potential crashes (SW)
authorJean-Philippe Andre <jp.andre@samsung.com>
Wed, 8 Apr 2015 08:21:42 +0000 (17:21 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Wed, 8 Apr 2015 09:17:34 +0000 (18:17 +0900)
Make sure not to sample the mask image outside its boundaries.
This is a series of last resort checks. I can not reproduce the
crashes but know they have happened.

I used EINA_UNLIKELY more for clarity than for compiler optimizations.

src/lib/evas/common/evas_font_compress.c
src/lib/evas/common/evas_rectangle_main.c
src/lib/evas/common/evas_scale_sample.c
src/lib/evas/common/evas_scale_smooth_scaler.c

index 6c84aa4..1e13e53 100644 (file)
@@ -534,6 +534,16 @@ evas_common_font_glyph_draw(RGBA_Font_Glyph *fg,
 
         buf = alloca(sizeof(DATA32) * w * h);
 
+        // Adjust clipping info
+        if (EINA_UNLIKELY((x + x1) < dc->clip.mask_x))
+          x1 = dc->clip.mask_x - x;
+        if (EINA_UNLIKELY((y + y1) < dc->clip.mask_y))
+          y1 = dc->clip.mask_y - y;
+        if (EINA_UNLIKELY((x + x2) > (int)(x + x1 + im->cache_entry.w)))
+          x2 = x1 + im->cache_entry.w;
+        if (EINA_UNLIKELY((y + y2) > (int)(y + y1 + im->cache_entry.h)))
+          y2 = y1 + im->cache_entry.h;
+
         // Step 1: alpha glyph drawing
         src8 = evas_common_font_glyph_uncompress(fg, NULL, NULL);
         if (!src8) return;
index d952f41..220fd0f 100644 (file)
@@ -135,7 +135,18 @@ rectangle_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, in
 #endif
      {
         if (mask_ie)
-          func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, w, dc->render_op);
+          {
+             func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, w, dc->render_op);
+             // Adjust clipping info
+             if (EINA_UNLIKELY((x - dc->clip.mask_x) < 0))
+               x = dc->clip.mask_x;
+             if (EINA_UNLIKELY((y - dc->clip.mask_y) < 0))
+               y = dc->clip.mask_y;
+             if (EINA_UNLIKELY((x - dc->clip.mask_x + w) > (int)mask_ie->cache_entry.w))
+               w = mask_ie->cache_entry.w + dc->clip.mask_x - x;
+             if (EINA_UNLIKELY((y - dc->clip.mask_y + h) > (int)mask_ie->cache_entry.h))
+               h = mask_ie->cache_entry.h + dc->clip.mask_y - y;
+          }
         else
           func = evas_common_gfx_func_composite_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, w, dc->render_op);
         ptr = dst->image.data + (y * dst->cache_entry.w) + x;
@@ -165,7 +176,18 @@ evas_common_rectangle_rgba_draw(RGBA_Image *dst, DATA32 color, int render_op, in
    int yy;
 
    if (mask_ie)
-     func = evas_common_gfx_func_composite_mask_color_span_get(color, dst->cache_entry.flags.alpha, w, render_op);
+     {
+        func = evas_common_gfx_func_composite_mask_color_span_get(color, dst->cache_entry.flags.alpha, w, render_op);
+        // Adjust clipping info
+        if (EINA_UNLIKELY((x - mask_x) < 0))
+          x = mask_x;
+        if (EINA_UNLIKELY((y - mask_y) < 0))
+          y = mask_y;
+        if (EINA_UNLIKELY((x - mask_x + w) > (int)mask_ie->cache_entry.w))
+          w = mask_ie->cache_entry.w + mask_x - x;
+        if (EINA_UNLIKELY((y - mask_y + h) > (int)mask_ie->cache_entry.h))
+          h = mask_ie->cache_entry.h + mask_y - y;
+     }
    else
      func = evas_common_gfx_func_composite_color_span_get(color, dst->cache_entry.flags.alpha, w, render_op);
 
index 40dd7f8..2de5632 100644 (file)
@@ -131,7 +131,7 @@ _evas_common_scale_rgba_sample_scale_mask(int y,
                                           int dst_clip_x, int dst_clip_y,
                                           int dst_clip_w, int dst_clip_h, int dst_w,
                                           int mask_x, int mask_y,
-                                          DATA32 **row_ptr, int *lin_ptr, RGBA_Image *im,
+                                          DATA32 **row_ptr, int *lin_ptr, RGBA_Image *mask_ie,
                                           DATA32 *dptr, RGBA_Gfx_Func func, RGBA_Gfx_Func func2,
                                           unsigned int mul_col)
 {
@@ -141,14 +141,24 @@ _evas_common_scale_rgba_sample_scale_mask(int y,
    /* a scanline buffer */
    buf = alloca(dst_clip_w * sizeof(DATA32));
 
+   // Adjust clipping info
+   if (EINA_UNLIKELY((dst_clip_x - mask_x) < 0))
+     dst_clip_x = mask_x;
+   if (EINA_UNLIKELY((dst_clip_y - mask_y + y) < 0))
+     dst_clip_y = mask_y + y;
+   if (EINA_UNLIKELY((dst_clip_x - mask_x + dst_clip_w) > (int)mask_ie->cache_entry.w))
+     dst_clip_w = mask_x - mask_ie->cache_entry.w - dst_clip_x;
+   if (EINA_UNLIKELY((dst_clip_y - mask_y + y + dst_clip_h) > (int)mask_ie->cache_entry.h))
+     dst_clip_h = mask_y + y - mask_ie->cache_entry.h - dst_clip_y;
+
    dptr = dptr + dst_w * y;
    for (; y < dst_clip_h; y++)
      {
         DATA8 *mask;
 
         dst_ptr = buf;
-        mask = im->image.data8
-          + ((dst_clip_y - mask_y + y) * im->cache_entry.w)
+        mask = mask_ie->image.data8
+          + ((dst_clip_y - mask_y + y) * mask_ie->cache_entry.w)
           + (dst_clip_x - mask_x);
 
         for (x = 0; x < dst_clip_w; x++)
@@ -325,6 +335,15 @@ evas_common_scale_rgba_sample_draw(RGBA_Image *src, RGBA_Image *dst, int dst_cli
           }
         else
           func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, render_op);
+        // Adjust clipping info
+        if (EINA_UNLIKELY((dst_clip_x - mask_x) < 0))
+          dst_clip_x = mask_x;
+        if (EINA_UNLIKELY((dst_clip_y - mask_y) < 0))
+          dst_clip_y = mask_y;
+        if (EINA_UNLIKELY((dst_clip_x - mask_x + dst_clip_w) > (int)mask_ie->cache_entry.w))
+          dst_clip_w = mask_ie->cache_entry.w - dst_clip_x + mask_x;
+        if (EINA_UNLIKELY((dst_clip_y - mask_y + dst_clip_h) > (int)mask_ie->cache_entry.h))
+          dst_clip_h = mask_ie->cache_entry.h - dst_clip_y + mask_y;
      }
 
    if ((dst_region_w == src_region_w) && (dst_region_h == src_region_h))
@@ -449,8 +468,9 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst,
    DATA32  *ptr, *dst_ptr, *src_data, *dst_data;
    DATA8   *mask;
    int      dst_clip_x, dst_clip_y, dst_clip_w, dst_clip_h;
-   int      src_w, src_h, dst_w, dst_h;
+   int      src_w, src_h, dst_w, dst_h, mask_x, mask_y;
    RGBA_Gfx_Func func, func2 = NULL;
+   RGBA_Image *mask_ie = dc->clip.mask;
 
    if (!(RECTS_INTERSECT(dst_region_x, dst_region_y, dst_region_w, dst_region_h, 0, 0, dst->cache_entry.w, dst->cache_entry.h)))
      return EINA_FALSE;
@@ -578,7 +598,7 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst,
    /* figure out dest start ptr */
    dst_ptr = dst_data + dst_clip_x + (dst_clip_y * dst_w);
 
-   if (!dc->clip.mask)
+   if (!mask_ie)
      {
         if (dc->mul.use)
           func = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dc->mul.col, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op);
@@ -590,6 +610,17 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst,
         func = evas_common_gfx_func_composite_pixel_mask_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dst->cache_entry.flags.alpha, dst_clip_w, dc->render_op);
         if (dc->mul.use)
           func2 = evas_common_gfx_func_composite_pixel_color_span_get(src->cache_entry.flags.alpha, src->cache_entry.flags.alpha_sparse, dc->mul.col, dst->cache_entry.flags.alpha, dst_clip_w, EVAS_RENDER_COPY);
+        // Adjust clipping info
+        mask_x = dc->clip.mask_x;
+        mask_y = dc->clip.mask_y;
+        if (EINA_UNLIKELY((dst_clip_x - mask_x) < 0))
+          dst_clip_x = mask_x;
+        if (EINA_UNLIKELY((dst_clip_y - mask_y) < 0))
+          dst_clip_y = mask_y;
+        if (EINA_UNLIKELY((dst_clip_x - mask_x + dst_clip_w) > (int)mask_ie->cache_entry.w))
+          dst_clip_w = mask_ie->cache_entry.w - dst_clip_x + mask_x;
+        if (EINA_UNLIKELY((dst_clip_y - mask_y + dst_clip_h) > (int)mask_ie->cache_entry.h))
+          dst_clip_h = mask_ie->cache_entry.h - dst_clip_y + mask_y;
      }
 
    if ((dst_region_w == src_region_w) && (dst_region_h == src_region_h))
@@ -621,18 +652,16 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst,
              ptr = src_data + ((dst_clip_y - dst_region_y + src_region_y) * src_w) + (dst_clip_x - dst_region_x) + src_region_x;
 
              /* image masking */
-             if (dc->clip.mask)
+             if (mask_ie)
                {
-                  RGBA_Image *im = dc->clip.mask;
-
                   if (dc->mul.use)
                     buf = alloca(dst_clip_w * sizeof(DATA32));
 
                   for (y = 0; y < dst_clip_h; y++)
                     {
-                       mask = im->image.data8
-                          + ((dst_clip_y - dc->clip.mask_y + y) * im->cache_entry.w)
-                          + (dst_clip_x - dc->clip.mask_x);
+                       mask = mask_ie->image.data8
+                          + ((dst_clip_y - mask_y + y) * mask_ie->cache_entry.w)
+                          + (dst_clip_x - mask_x);
 
                        /* * blend here [clip_w *] ptr -> dst_ptr * */
                        if (dc->mul.use)
@@ -723,8 +752,8 @@ scale_rgba_in_to_out_clip_sample_internal(RGBA_Image *src, RGBA_Image *dst,
                   local.dst_clip_h = dst_clip_h;
                   local.dst_clip_w = dst_clip_w;
                   local.dst_w = dst_w;
-                  local.mask_x = dc->clip.mask_x;
-                  local.mask_y = dc->clip.mask_y;
+                  local.mask_x = mask_x;
+                  local.mask_y = mask_y;
                   local.mul_col = mul_col;
 
                   msg = eina_thread_queue_send(thread_queue, sizeof (Evas_Scale_Msg), &ref);
index 0eea162..24bc28e 100644 (file)
@@ -131,6 +131,19 @@ SCALE_FUNC(RGBA_Image *src, RGBA_Image *dst, int dst_clip_x, int dst_clip_y, int
    /* figure out dest start ptr */
    dst_ptr = dst->image.data + dst_clip_x + (dst_clip_y * dst_w);
 
+   if (mask_ie)
+     {
+        // Adjust clipping info
+        if (EINA_UNLIKELY((dst_clip_x - mask_x) < 0))
+          dst_clip_x = mask_x;
+        if (EINA_UNLIKELY((dst_clip_y - mask_y) < 0))
+          dst_clip_y = mask_y;
+        if (EINA_UNLIKELY((dst_clip_x - mask_x + dst_clip_w) > (int)mask_ie->cache_entry.w))
+          dst_clip_w = mask_ie->cache_entry.w - dst_clip_x + mask_x;
+        if (EINA_UNLIKELY((dst_clip_y - mask_y + dst_clip_h) > (int)mask_ie->cache_entry.h))
+          dst_clip_h = mask_ie->cache_entry.h - dst_clip_y + mask_y;
+     }
+
 /* FIXME:
  *
  * things to do later for speedups: