From 5d8069b4404b7d4be5f513682c17b52cf83f7483 Mon Sep 17 00:00:00 2001
From: Martchus <martchus@gmx.net>
Date: Sat, 26 Jun 2021 22:24:12 +0200
Subject: [PATCH 32/32] Fix crashes in rasterization code using setjmp
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Use C++ exceptions instead of setjmp to workaround crashes
* The setjmp/longjmp code crashes when compiling for x86_64-w64-mingw32
  with GCC 11 and optimizations enabled¹. It crashes when jumping back
  to handle the case of insufficient memory. This change uses C++
  exceptions instead (turning the compile unit into a C++ unit instead
  of just using C) which should behave identical but don't seem to
  crash.
* Fix rendering certain SVGs and possibly other graphics

Change-Id: I01937d13569dd01ab4cb1f608020544c93bc343c

---

¹ See https://bugreports.qt.io/browse/QTBUG-94692 for details.
---
 src/gui/painting/painting.pri                 |  4 +-
 .../{qgrayraster.c => qgrayraster.cpp}        | 41 ++++++++-----------
 src/gui/painting/qt_attribution.json          |  2 +-
 3 files changed, 21 insertions(+), 26 deletions(-)
 rename src/gui/painting/{qgrayraster.c => qgrayraster.cpp} (98%)

diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index bb0fc0ffba..72decdefbf 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -1,5 +1,7 @@
 # Qt gui library, paint module
 
+CONFIG += exceptions
+
 HEADERS += \
         painting/qbackingstore.h \
         painting/qbezier_p.h \
@@ -80,7 +82,7 @@ SOURCES += \
         painting/qcosmeticstroker.cpp \
         painting/qdrawhelper.cpp \
         painting/qemulationpaintengine.cpp \
-        painting/qgrayraster.c \
+        painting/qgrayraster.cpp \
         painting/qicc.cpp \
         painting/qimagescale.cpp \
         painting/qmatrix.cpp \
diff --git a/src/gui/painting/qgrayraster.c b/src/gui/painting/qgrayraster.cpp
similarity index 98%
rename from src/gui/painting/qgrayraster.c
rename to src/gui/painting/qgrayraster.cpp
index 0143e9b602..803a676e1a 100644
--- a/src/gui/painting/qgrayraster.c
+++ b/src/gui/painting/qgrayraster.cpp
@@ -39,7 +39,7 @@
 
 /***************************************************************************/
 /*                                                                         */
-/*  qgrayraster.c, derived from ftgrays.c                                  */
+/*  qgrayraster.cpp, derived from ftgrays.c                                */
 /*                                                                         */
 /*    A new `perfect' anti-aliasing renderer (body).                       */
 /*                                                                         */
@@ -157,17 +157,12 @@
 #  include <vxWorksCommon.h>    /* needed for setjmp.h */
 #endif
 #include <string.h>             /* for qt_ft_memcpy() */
-#include <setjmp.h>
 #include <limits.h>
 
 #define QT_FT_UINT_MAX  UINT_MAX
 
 #define qt_ft_memset   memset
 
-#define qt_ft_setjmp   setjmp
-#define qt_ft_longjmp  longjmp
-#define qt_ft_jmp_buf  jmp_buf
-
 #include <stddef.h>
 typedef ptrdiff_t  QT_FT_PtrDist;
 
@@ -177,6 +172,8 @@ typedef ptrdiff_t  QT_FT_PtrDist;
 #define ErrRaster_Memory_Overflow   -4
 #define ErrRaster_OutOfMemory       -6
 
+struct RasterMemoryOverflow {};
+
 #define QT_FT_BEGIN_HEADER
 #define QT_FT_END_HEADER
 
@@ -312,8 +309,6 @@ QT_FT_END_STMNT
     int  band_size;
     int  band_shoot;
 
-    qt_ft_jmp_buf  jump_buffer;
-
     void*       buffer;
     long        buffer_size;
 
@@ -335,12 +330,14 @@ QT_FT_END_STMNT
 
   } TRaster, *PRaster;
 
+  extern "C" {
   int q_gray_rendered_spans(TRaster *raster)
   {
     if ( raster && raster->worker )
       return raster->worker->skip_spans > 0 ? 0 : -raster->worker->skip_spans;
     return 0;
   }
+  }
 
   /*************************************************************************/
   /*                                                                       */
@@ -406,7 +403,6 @@ QT_FT_END_STMNT
     ras.max_ey = ( ras.max_ey + 63 ) >> 6;
   }
 
-
   /*************************************************************************/
   /*                                                                       */
   /* Record the current cell in the table.                                 */
@@ -435,7 +431,7 @@ QT_FT_END_STMNT
     }
 
     if ( ras.num_cells >= ras.max_cells )
-      qt_ft_longjmp( ras.jump_buffer, 1 );
+      throw RasterMemoryOverflow();
 
     cell        = ras.cells + ras.num_cells++;
     cell->x     = x;
@@ -1507,7 +1503,7 @@ QT_FT_END_STMNT
 
       QT_FT_TRACE5(( "  move to (%.2f, %.2f)\n",
                      v_start.x / 64.0, v_start.y / 64.0 ));
-      error = gray_move_to( &v_start, user );
+      error = gray_move_to( &v_start, static_cast<PWorker>(user) );
       if ( error )
         goto Exit;
 
@@ -1529,7 +1525,7 @@ QT_FT_END_STMNT
 
             QT_FT_TRACE5(( "  line to (%.2f, %.2f)\n",
                            vec.x / 64.0, vec.y / 64.0 ));
-            gray_render_line(user, UPSCALE(vec.x), UPSCALE(vec.y));
+            gray_render_line(static_cast<PWorker>(user), UPSCALE(vec.x), UPSCALE(vec.y));
             continue;
           }
 
@@ -1558,7 +1554,7 @@ QT_FT_END_STMNT
                                " with control (%.2f, %.2f)\n",
                                vec.x / 64.0, vec.y / 64.0,
                                v_control.x / 64.0, v_control.y / 64.0 ));
-                gray_render_conic(user, &v_control, &vec);
+                gray_render_conic(static_cast<PWorker>(user), &v_control, &vec);
                 continue;
               }
 
@@ -1572,7 +1568,7 @@ QT_FT_END_STMNT
                              " with control (%.2f, %.2f)\n",
                              v_middle.x / 64.0, v_middle.y / 64.0,
                              v_control.x / 64.0, v_control.y / 64.0 ));
-              gray_render_conic(user, &v_control, &v_middle);
+              gray_render_conic(static_cast<PWorker>(user), &v_control, &v_middle);
 
               v_control = vec;
               goto Do_Conic;
@@ -1582,7 +1578,7 @@ QT_FT_END_STMNT
                            " with control (%.2f, %.2f)\n",
                            v_start.x / 64.0, v_start.y / 64.0,
                            v_control.x / 64.0, v_control.y / 64.0 ));
-            gray_render_conic(user, &v_control, &v_start);
+            gray_render_conic(static_cast<PWorker>(user), &v_control, &v_start);
             goto Close;
           }
 
@@ -1617,7 +1613,7 @@ QT_FT_END_STMNT
                              vec.x / 64.0, vec.y / 64.0,
                              vec1.x / 64.0, vec1.y / 64.0,
                              vec2.x / 64.0, vec2.y / 64.0 ));
-              gray_render_cubic(user, &vec1, &vec2, &vec);
+              gray_render_cubic(static_cast<PWorker>(user), &vec1, &vec2, &vec);
               continue;
             }
 
@@ -1626,7 +1622,7 @@ QT_FT_END_STMNT
                            v_start.x / 64.0, v_start.y / 64.0,
                            vec1.x / 64.0, vec1.y / 64.0,
                            vec2.x / 64.0, vec2.y / 64.0 ));
-            gray_render_cubic(user, &vec1, &vec2, &v_start);
+            gray_render_cubic(static_cast<PWorker>(user), &vec1, &vec2, &v_start);
             goto Close;
           }
         }
@@ -1635,7 +1631,7 @@ QT_FT_END_STMNT
       /* close the contour with a line segment */
       QT_FT_TRACE5(( "  line to (%.2f, %.2f)\n",
                      v_start.x / 64.0, v_start.y / 64.0 ));
-      gray_render_line(user, UPSCALE(v_start.x), UPSCALE(v_start.y));
+      gray_render_line(static_cast<PWorker>(user), UPSCALE(v_start.x), UPSCALE(v_start.y));
 
    Close:
       first = last + 1;
@@ -1663,14 +1659,11 @@ QT_FT_END_STMNT
   {
     volatile int  error = 0;
 
-    if ( qt_ft_setjmp( ras.jump_buffer ) == 0 )
-    {
+    try {
       error = QT_FT_Outline_Decompose( &ras.outline, &ras );
       if ( !ras.invalid )
         gray_record_cell( RAS_VAR );
-    }
-    else
-    {
+    } catch (const RasterMemoryOverflow &) {
       error = ErrRaster_Memory_Overflow;
     }
 
@@ -1932,7 +1925,7 @@ QT_FT_END_STMNT
   static int
   gray_raster_new( QT_FT_Raster*  araster )
   {
-    *araster = malloc(sizeof(TRaster));
+    *araster = static_cast<TRaster *>(malloc(sizeof(TRaster)));
     if (!*araster) {
         *araster = 0;
         return ErrRaster_Memory_Overflow;
diff --git a/src/gui/painting/qt_attribution.json b/src/gui/painting/qt_attribution.json
index 0e87d30aa2..8566ce0048 100644
--- a/src/gui/painting/qt_attribution.json
+++ b/src/gui/painting/qt_attribution.json
@@ -4,7 +4,7 @@
         "Name": "Anti-aliasing rasterizer from FreeType 2",
         "QDocModule": "qtgui",
         "QtUsage": "Used in Qt GUI.",
-        "Path": "qgrayraster.c",
+        "Path": "qgrayraster.cpp",
 
         "Description": "FreeType is a freely available software library to render fonts.",
         "Homepage": "http://www.freetype.org",
-- 
2.41.0

