Commit 06e21ffedfac81edfa79137959141a9d78b6f858

Ben Wagner 2021-05-18T14:49:50

[gzip] Use exact type for `ft_gzip_alloc` and `ft_gzip_free`. While a function pointer may be cast to another function pointer type, it is required to cast the function pointer back to the original function pointer type before calling it. If a parameter is a pointer the exact pointer type is required. Using a pointer to a different underlying type is technically undefined behavior. The wrapper functions `ft_gzip_alloc` and `ft_gzip_free` took `FT_Memory` (a `FT_MemoryRec_*`) instead of `voidpf` (`void*`), so when gzip calls these callbacks through `alloc_func` or `free_func` it invokes undefined behavior. On most platforms this works out as expected, but newer undefined behavior detectors and targets like wasm can detect this and will produce an error. * src/gzip/ftgzip.c (ft_gzip_alloc, ft_gzip_free): Update signatures to exactly match `alloc_func` and `free_func`, respectively. Internally, cast the `void*` opaque pointer to `FT_Memory`.

diff --git a/ChangeLog b/ChangeLog
index 0ec6870..d3583a4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2021-05-19  Ben Wagner  <bungeman@chromium.org>
+
+	[gzip] Use exact type for `ft_gzip_alloc` and `ft_gzip_free`.
+
+	While a function pointer may be cast to another function pointer
+	type, it is required to cast the function pointer back to the
+	original function pointer type before calling it.  If a parameter is
+	a pointer the exact pointer type is required.  Using a pointer to a
+	different underlying type is technically undefined behavior.  The
+	wrapper functions `ft_gzip_alloc` and `ft_gzip_free` took
+	`FT_Memory` (a `FT_MemoryRec_*`) instead of `voidpf` (`void*`), so
+	when gzip calls these callbacks through `alloc_func` or `free_func`
+	it invokes undefined behavior.  On most platforms this works out as
+	expected, but newer undefined behavior detectors and targets like
+	wasm can detect this and will produce an error.
+
+	* src/gzip/ftgzip.c (ft_gzip_alloc, ft_gzip_free): Update signatures
+	to exactly match `alloc_func` and `free_func`, respectively.
+	Internally, cast the `void*` opaque pointer to `FT_Memory`.
+
 2021-05-18  Alexei Podtelezhnikov  <apodtele@gmail.com>
 
 	Prioritize the anti-aliasing renderer module.
diff --git a/src/gzip/ftgzip.c b/src/gzip/ftgzip.c
index 0dc0a61..788a37b 100644
--- a/src/gzip/ftgzip.c
+++ b/src/gzip/ftgzip.c
@@ -121,13 +121,14 @@
      'malloc/free' */
 
   static voidpf
-  ft_gzip_alloc( FT_Memory  memory,
-                 uInt       items,
-                 uInt       size )
+  ft_gzip_alloc( voidpf  opaque,
+                 uInt    items,
+                 uInt    size )
   {
-    FT_ULong    sz = (FT_ULong)size * items;
+    FT_Memory   memory = (FT_Memory)opaque;
+    FT_ULong    sz     = (FT_ULong)size * items;
     FT_Error    error;
-    FT_Pointer  p  = NULL;
+    FT_Pointer  p      = NULL;
 
 
     /* allocate and zero out */
@@ -137,9 +138,12 @@
 
 
   static void
-  ft_gzip_free( FT_Memory  memory,
-                voidpf     address )
+  ft_gzip_free( voidpf  opaque,
+                voidpf  address )
   {
+    FT_Memory  memory = (FT_Memory)opaque;
+
+
     FT_MEM_FREE( address );
   }
 
@@ -151,14 +155,14 @@
             unsigned  items,
             unsigned  size )
   {
-    return ft_gzip_alloc( (FT_Memory)opaque, items, size );
+    return ft_gzip_alloc( opaque, items, size );
   }
 
   local void
   zcfree( voidpf  opaque,
           voidpf  ptr )
   {
-    ft_gzip_free( (FT_Memory)opaque, ptr );
+    ft_gzip_free( opaque, ptr );
   }
 
 #endif /* !SYSTEM_ZLIB && !USE_ZLIB_ZCALLOC */
@@ -305,8 +309,8 @@
     }
 
     /* initialize zlib -- there is no zlib header in the compressed stream */
-    zstream->zalloc = (alloc_func)ft_gzip_alloc;
-    zstream->zfree  = (free_func) ft_gzip_free;
+    zstream->zalloc = ft_gzip_alloc;
+    zstream->zfree  = ft_gzip_free;
     zstream->opaque = stream->memory;
 
     zstream->avail_in = 0;
@@ -742,8 +746,8 @@
     stream.next_out  = output;
     stream.avail_out = (uInt)*output_len;
 
-    stream.zalloc = (alloc_func)ft_gzip_alloc;
-    stream.zfree  = (free_func) ft_gzip_free;
+    stream.zalloc = ft_gzip_alloc;
+    stream.zfree  = ft_gzip_free;
     stream.opaque = memory;
 
     /* This is a temporary fix and will be removed once the internal