[Bf-blender-cvs] [45d100208e8] master: Makesdna: Fix detecting 32 bit padding issues.

Ray Molenkamp noreply at git.blender.org
Thu Aug 12 03:20:59 CEST 2021


Commit: 45d100208e8fc07e65d4cad303fa353e85bf8747
Author: Ray Molenkamp
Date:   Wed Aug 11 19:20:51 2021 -0600
Branches: master
https://developer.blender.org/rB45d100208e8fc07e65d4cad303fa353e85bf8747

Makesdna: Fix detecting 32 bit padding issues.

Makesdna fails to detect issues in 32 bit code that can
only be resolved by adding a padding pointer.

We never noticed since we ourselves no longer build for
32 bit, but debian's 32 bit builds got bitten by this

A rather extensive explanation on why this is alignment
requirement is there can be found in this comment:

https://developer.blender.org/D9389#233034

Differential Revision: https://developer.blender.org/D12188

Reviewed by: sergey, campbellbarton

===================================================================

M	source/blender/makesdna/intern/makesdna.c

===================================================================

diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index f2a75a60a44..8324db1a9c8 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -165,6 +165,10 @@ static char **names;
 static char **types;
 /** At `types_size[a]` is the size of type `a` on this systems bitness (32 or 64). */
 static short *types_size_native;
+/** Contains align requirements for a struct on 32 bit systems. */
+static short *types_align_32;
+/** Contains align requirements for a struct on 64 bit systems. */
+static short *types_align_64;
 /** Contains sizes as they are calculated on 32 bit systems. */
 static short *types_size_32;
 /** Contains sizes as they are calculated on 64 bit systems. */
@@ -406,6 +410,8 @@ static int add_type(const char *str, int size)
         types_size_native[index] = size;
         types_size_32[index] = size;
         types_size_64[index] = size;
+        types_align_32[index] = size;
+        types_align_64[index] = size;
       }
       return index;
     }
@@ -419,7 +425,8 @@ static int add_type(const char *str, int size)
   types_size_native[types_len] = size;
   types_size_32[types_len] = size;
   types_size_64[types_len] = size;
-
+  types_align_32[types_len] = size;
+  types_align_64[types_len] = size;
   if (types_len >= max_array_len) {
     printf("too many types\n");
     return types_len - 1;
@@ -966,7 +973,9 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char
         int size_native = 0;
         int size_32 = 0;
         int size_64 = 0;
-        bool has_pointer = false;
+        /* Sizes of the largest field in a struct. */
+        int max_align_32 = 0;
+        int max_align_64 = 0;
 
         /* check all elements in struct */
         for (int b = 0; b < structpoin[1]; b++, sp += 2) {
@@ -995,7 +1004,6 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char
 
           /* is it a pointer or function pointer? */
           if (cp[0] == '*' || cp[1] == '*') {
-            has_pointer = 1;
             /* has the name an extra length? (array) */
             int mul = 1;
             if (cp[namelen - 1] == ']') {
@@ -1042,6 +1050,8 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char
             size_native += sizeof(void *) * mul;
             size_32 += 4 * mul;
             size_64 += 8 * mul;
+            max_align_32 = MAX2(max_align_32, 4);
+            max_align_64 = MAX2(max_align_64, 8);
           }
           else if (cp[0] == '[') {
             /* parsing can cause names "var" and "[3]"
@@ -1087,6 +1097,8 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char
             size_native += mul * types_size_native[type];
             size_32 += mul * types_size_32[type];
             size_64 += mul * types_size_64[type];
+            max_align_32 = MAX2(max_align_32, types_align_32[type]);
+            max_align_64 = MAX2(max_align_64, types_align_64[type]);
           }
           else {
             size_native = 0;
@@ -1103,16 +1115,42 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char
           types_size_native[structtype] = size_native;
           types_size_32[structtype] = size_32;
           types_size_64[structtype] = size_64;
-          /* Two ways to detect if a struct contains a pointer:
-           * has_pointer is set or size_native doesn't match any of 32/64bit lengths. */
-          if (has_pointer || size_64 != size_native || size_32 != size_native) {
-            if (size_64 % 8) {
+          types_align_32[structtype] = max_align_32;
+          types_align_64[structtype] = max_align_64;
+
+          /* Santiy check 1: alignment should never be 0. */
+          BLI_assert(max_align_32);
+          BLI_assert(max_align_64);
+
+          /* Santiy check 2: alignment should always be equal or smaller than the maximum
+           * size of a build in type which is 8 bytes (ie int64_t or double). */
+          BLI_assert(max_align_32 <= 8);
+          BLI_assert(max_align_64 <= 8);
+
+          if (size_32 % max_align_32) {
+            /* There is an one odd case where only the 32 bit struct has alignment issues
+             * and the 64 bit does not, that can only be fixed by adding a padding pointer
+             * to the struct to resolve the problem. */
+            if ((size_64 % max_align_64 == 0) && (size_32 % max_align_32 == 4)) {
               fprintf(stderr,
-                      "Sizeerror 8 in struct: %s (add %d bytes)\n",
+                      "Sizeerror in 32 bit struct: %s (add paddding pointer)\n",
+                      types[structtype]);
+            }
+            else {
+              fprintf(stderr,
+                      "Sizeerror in 32 bit struct: %s (add %d bytes)\n",
                       types[structtype],
-                      size_64 % 8);
-              dna_error = 1;
+                      max_align_32 - (size_32 % max_align_32));
             }
+            dna_error = 1;
+          }
+
+          if (size_64 % max_align_64) {
+            fprintf(stderr,
+                    "Sizeerror in 64 bit struct: %s (add %d bytes)\n",
+                    types[structtype],
+                    max_align_64 - (size_64 % max_align_64));
+            dna_error = 1;
           }
 
           if (size_native % 4 && !ELEM(size_native, 1, 2)) {
@@ -1229,6 +1267,9 @@ static int make_structDNA(const char *base_directory,
   types_size_native = MEM_callocN(sizeof(short) * max_array_len, "types_size_native");
   types_size_32 = MEM_callocN(sizeof(short) * max_array_len, "types_size_32");
   types_size_64 = MEM_callocN(sizeof(short) * max_array_len, "types_size_64");
+  types_align_32 = MEM_callocN(sizeof(short) * max_array_len, "types_size_32");
+  types_align_64 = MEM_callocN(sizeof(short) * max_array_len, "types_size_64");
+
   structs = MEM_callocN(sizeof(short *) * max_array_len, "structs");
 
   /* Build versioning data */
@@ -1317,7 +1358,11 @@ static int make_structDNA(const char *base_directory,
       sp += 2;
       /* ? num_types was elem? */
       for (b = 0; b < num_types; b++, sp += 2) {
-        printf("   %s %s\n", types[sp[0]], names[sp[1]]);
+        printf("   %s %s allign32:%d, allign64:%d\n",
+               types[sp[0]],
+               names[sp[1]],
+               types_align_32[sp[0]],
+               types_align_64[sp[0]]);
       }
     }
   }
@@ -1439,6 +1484,8 @@ static int make_structDNA(const char *base_directory,
   MEM_freeN(types_size_native);
   MEM_freeN(types_size_32);
   MEM_freeN(types_size_64);
+  MEM_freeN(types_align_32);
+  MEM_freeN(types_align_64);
   MEM_freeN(structs);
 
   BLI_memarena_free(mem_arena);



More information about the Bf-blender-cvs mailing list