From 3a6c3bf10d77edc588264f496f4a437579223fb7 Mon Sep 17 00:00:00 2001
From: Martchus <martchus@gmx.net>
Date: Sat, 26 Jun 2021 22:24:12 +0200
Subject: [PATCH] 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/CMakeLists.txt                        |  7 +++-
 .../{qgrayraster.c => qgrayraster.cpp}        | 41 ++++++++-----------
 src/gui/painting/qt_attribution.json          |  2 +-
 3 files changed, 24 insertions(+), 26 deletions(-)
 rename src/gui/painting/{qgrayraster.c => qgrayraster.cpp} (98%)

diff --git a/qtbase/src/gui/CMakeLists.txt b/qtbase/src/gui/CMakeLists.txt
index 5b8bc278e9d..e3e2ca1829d 100644
--- a/qtbase/src/gui/CMakeLists.txt
+++ b/qtbase/src/gui/CMakeLists.txt
@@ -175,7 +175,7 @@ qt_internal_add_module(Gui
         painting/qdrawingprimitive_sse2_p.h
         painting/qemulationpaintengine.cpp painting/qemulationpaintengine_p.h
         painting/qfixed_p.h
-        painting/qgrayraster.c painting/qgrayraster_p.h
+        painting/qgrayraster.cpp painting/qgrayraster_p.h
         painting/qicc.cpp painting/qicc_p.h
         painting/qimagescale.cpp painting/qimagescale_p.h
         painting/qmath_p.h
@@ -284,6 +284,11 @@ qt_internal_add_module(Gui
         "(^|/)qplatform.+\\.h$|(^|/)qwindowsystem.+\\.h$"
 )
 
+# enable exceptions for painting/qgrayraster.cpp
+set_source_files_properties("painting/qgrayraster.cpp"
+    PROPERTIES COMPILE_FLAGS "-fexceptions" DISABLE_PRECOMPILE_HEADERS ON SKIP_PRECOMPILE_HEADERS ON
+)
+
 # Resources:
 set_source_files_properties("../3rdparty/icc/sRGB2014.icc"
     PROPERTIES QT_RESOURCE_ALIAS "sRGB2014.icc"
diff --git a/qtbase/src/gui/painting/qgrayraster.c b/qtbase/src/gui/painting/qgrayraster.cpp
similarity index 98%
rename from src/gui/painting/qgrayraster.c
rename to src/gui/painting/qgrayraster.cpp
index 3c222c49e16..813cfc08dcf 100644
--- a/qtbase/src/gui/painting/qgrayraster.c
+++ b/qtbase/src/gui/painting/qgrayraster.cpp
@@ -3,7 +3,7 @@
 
 /***************************************************************************/
 /*                                                                         */
-/*  qgrayraster.c, derived from ftgrays.c                                  */
+/*  qgrayraster.cpp, derived from ftgrays.c                                */
 /*                                                                         */
 /*    A new `perfect' anti-aliasing renderer (body).                       */
 /*                                                                         */
@@ -121,17 +121,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;
 
@@ -141,6 +136,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
 
@@ -274,8 +271,6 @@ QT_FT_END_STMNT
     int  band_size;
     int  band_shoot;
 
-    qt_ft_jmp_buf  jump_buffer;
-
     void*       buffer;
     long        buffer_size;
 
@@ -297,12 +292,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;
   }
+  }
 
   /*************************************************************************/
   /*                                                                       */
@@ -368,7 +365,6 @@ QT_FT_END_STMNT
     ras.max_ey = ( ras.max_ey + 63 ) >> 6;
   }
 
-
   /*************************************************************************/
   /*                                                                       */
   /* Record the current cell in the table.                                 */
@@ -397,7 +393,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;
@@ -1470,7 +1466,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;
 
@@ -1492,7 +1488,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;
           }
 
@@ -1521,7 +1517,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;
               }
 
@@ -1535,7 +1531,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;
@@ -1545,7 +1541,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;
           }
 
@@ -1580,7 +1576,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;
             }
 
@@ -1589,7 +1585,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;
           }
         }
@@ -1598,7 +1594,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;
@@ -1626,14 +1622,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;
     }
 
@@ -1898,7 +1891,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/qtbase/src/gui/painting/qt_attribution.json b/qtbase/src/gui/painting/qt_attribution.json
index d0f2468e6a0..d1d7d2e17ad 100644
--- a/qtbase/src/gui/painting/qt_attribution.json
+++ b/qtbase/src/gui/painting/qt_attribution.json
@@ -4,7 +4,7 @@
         "Name": "Anti-aliasing rasterizer from FreeType 2",
         "QDocModule": "qtgui",
         "QtUsage": "Used in Qt GUI.",
-        "Files": "qgrayraster.c",
+        "Files": "qgrayraster.cpp",
 
         "Description": "FreeType is a freely available software library to render fonts.",
         "Homepage": "http://www.freetype.org",
