Commit 3b3cb32dd2340d86d3165961a4bb3dbd44353075

Werner Lemberg 2017-09-21T09:03:20

[truetype] Fix `mmvar' array pointers. Without this change, clang's AddressSanitizer reports many runtime errors due to misaligned addresses. * src/truetype/ttgxvar.c (TT_Get_MM_Var): Use multiples of pointer size for sub-array offsets into `mmvar'.

diff --git a/ChangeLog b/ChangeLog
index f08b56a..ab5530f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2017-09-21  Werner Lemberg  <wl@gnu.org>
+
+	[truetype] Fix `mmvar' array pointers.
+
+	Without this change, clang's AddressSanitizer reports many runtime
+	errors due to misaligned addresses.
+
+	* src/truetype/ttgxvar.c (TT_Get_MM_Var): Use multiples of pointer
+	size for sub-array offsets into `mmvar'.
+
 2017-09-20  Werner Lemberg  <wl@gnu.org>
 
 	[truetype] Integer overflows.
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index 49aa53a..8c56c56 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -1997,6 +1997,14 @@
 
     if ( !face->blend )
     {
+      FT_Offset  mmvar_size;
+      FT_Offset  axis_flags_size;
+      FT_Offset  axis_size;
+      FT_Offset  namedstyle_size;
+      FT_Offset  next_coords_size;
+      FT_Offset  next_name_size;
+
+
       FT_TRACE2(( "FVAR " ));
 
       /* both `fvar' and `gvar' must be present */
@@ -2045,13 +2053,34 @@
       /* prepare storage area for MM data; this cannot overflow   */
       /* 32-bit arithmetic because of the size limits used in the */
       /* `fvar' table validity check in `sfnt_init_face'          */
-      face->blend->mmvar_len =
-        sizeof ( FT_MM_Var ) +
-        fvar_head.axisCount * sizeof ( FT_UShort ) +
-        fvar_head.axisCount * sizeof ( FT_Var_Axis ) +
-        num_instances * sizeof ( FT_Var_Named_Style ) +
-        num_instances * fvar_head.axisCount * sizeof ( FT_Fixed ) +
-        fvar_head.axisCount * 5;
+
+      /* the various `*_size' variables, which we also use as     */
+      /* offsets into the `mmlen' array, must be multiples of the */
+      /* pointer size (except the last one); without such an      */
+      /* alignment there might be runtime errors due to           */
+      /* misaligned addresses                                     */
+#undef  ALIGN_SIZE
+#define ALIGN_SIZE( n ) \
+          ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) )
+
+      mmvar_size       = ALIGN_SIZE( sizeof ( FT_MM_Var ) );
+      axis_flags_size  = ALIGN_SIZE( fvar_head.axisCount *
+                                     sizeof ( FT_UShort ) );
+      axis_size        = ALIGN_SIZE( fvar_head.axisCount *
+                                     sizeof ( FT_Var_Axis ) );
+      namedstyle_size  = ALIGN_SIZE( num_instances *
+                                     sizeof ( FT_Var_Named_Style ) );
+      next_coords_size = ALIGN_SIZE( num_instances *
+                                     fvar_head.axisCount *
+                                     sizeof ( FT_Fixed ) );
+      next_name_size   = fvar_head.axisCount * 5;
+
+      face->blend->mmvar_len = mmvar_size       +
+                               axis_flags_size  +
+                               axis_size        +
+                               namedstyle_size  +
+                               next_coords_size +
+                               next_name_size;
 
       if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
         goto Exit;
@@ -2071,21 +2100,22 @@
 
       /* alas, no public field in `FT_Var_Axis' for axis flags */
       axis_flags =
-        (FT_UShort*)&( mmvar[1] );
+        (FT_UShort*)( (char*)mmvar + mmvar_size );
       mmvar->axis =
-        (FT_Var_Axis*)&( axis_flags[fvar_head.axisCount] );
+        (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size );
       mmvar->namedstyle =
-        (FT_Var_Named_Style*)&( mmvar->axis[fvar_head.axisCount] );
+        (FT_Var_Named_Style*)( (char*)mmvar->axis + axis_size );
 
-      next_coords =
-        (FT_Fixed*)&( mmvar->namedstyle[num_instances] );
+      next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle +
+                                 namedstyle_size );
       for ( i = 0; i < num_instances; i++ )
       {
         mmvar->namedstyle[i].coords  = next_coords;
         next_coords                 += fvar_head.axisCount;
       }
 
-      next_name = (FT_String*)next_coords;
+      next_name = (FT_String*)( (char*)mmvar->namedstyle +
+                                namedstyle_size + next_coords_size );
       for ( i = 0; i < fvar_head.axisCount; i++ )
       {
         mmvar->axis[i].name  = next_name;