ecpg: fix some memory age of data-type-related structures.
authorTom Lane <[email protected]>
Wed, 27 Nov 2024 17:41:20 +0000 (12:41 -0500)
committerTom Lane <[email protected]>
Wed, 27 Nov 2024 17:50:23 +0000 (12:50 -0500)
ECPGfree_type() and related functions were quite incomplete
about removing subsidiary data structures.  Possibly this is
because ecpg wasn't careful to make sure said data structures
always had their own storage.  Previous es in this series
cleaned up a lot of that, and I had to add a couple more
mm_strdup's here.

Also, ecpg.trailer tended to overwrite struct_member_list[struct_level]
without bothering to free up its previous contents, thus potentially
ing a lot of struct-member-related storage.  Add
ECPGfree_struct_member() calls at appropriate points.

Discussion: https://postgr.es/m/2011420.1713493114@sss.pgh.pa.us

src/interfaces/ecpg/preproc/ecpg.header
src/interfaces/ecpg/preproc/ecpg.trailer
src/interfaces/ecpg/preproc/type.c
src/interfaces/ecpg/preproc/type.h
src/interfaces/ecpg/preproc/variable.c

index a415780faffeac8bd60282b9b63eb3911227a5df..e79b6b0de8ca428bc9605608417e05e3879e1a7d 100644 (file)
@@ -44,7 +44,19 @@ static char *actual_startline[STRUCT_DEPTH];
 static int varchar_counter = 1;
 static int bytea_counter = 1;
 
-/* temporarily store struct members while creating the data structure */
+/*
+ * We temporarily store struct members here while parsing struct declarations.
+ * The struct_member_list (at a given nesting depth) is constructed while
+ * scanning the fields within "struct { .... }", but we can't remove it upon
+ * seeing the right brace.  It's kept around and copied into the variables
+ * or typedefs that follow, in order to handle cases like
+ * "struct foo { ... } foovar1, foovar2;".  We recycle the storage only
+ * upon closing the current nesting level or starting the next struct
+ * declaration within the same nesting level.
+ * For cases like "struct foo foovar1, foovar2;", we copy the saved struct
+ * field list for the typedef or struct tag into the struct_member_list
+ * global variable, and then copy it again to the newly-declared variables.
+ */
 struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = {NULL};
 
 /* also store struct type so we can do a sizeof() later */
@@ -507,11 +519,12 @@ add_typedef(const char *name, const char *dimension, const char *length,
        this->name = mm_strdup(name);
        this->brace_level = braces_open;
        this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
+       this->type->type_storage = NULL;
        this->type->type_enum = type_enum;
        this->type->type_str = mm_strdup(name);
        this->type->type_dimension = mm_strdup(dimension); /* dimension of array */
        this->type->type_index = mm_strdup(length); /* length of string */
-       this->type->type_sizeof = ECPGstruct_sizeof;
+       this->type->type_sizeof = ECPGstruct_sizeof ? mm_strdup(ECPGstruct_sizeof) : NULL;
        this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ?
            ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL;
 
index 424903f76e092e8cbbf1929e00d3cd6c63e95f34..321bcbccac7b911dee94e9f5cf6c9d9f07a002e6 100644 (file)
@@ -755,6 +755,7 @@ var_type: simple_type
            else
                $$.type_sizeof = cat_str(3, "sizeof(", this->name, ")");
 
+           ECPGfree_struct_member(struct_member_list[struct_level]);
            struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
        }
    }
@@ -882,6 +883,7 @@ var_type: simple_type
            else
                $$.type_sizeof = cat_str(3, "sizeof(", this->name, ")");
 
+           ECPGfree_struct_member(struct_member_list[struct_level]);
            struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
        }
    }
@@ -904,6 +906,7 @@ var_type: simple_type
            $$.type_dimension = this->type->type_dimension;
            $$.type_index = this->type->type_index;
            $$.type_sizeof = this->type->type_sizeof;
+           ECPGfree_struct_member(struct_member_list[struct_level]);
            struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
        }
        else
@@ -913,6 +916,7 @@ var_type: simple_type
            $$.type_dimension = "-1";
            $$.type_index = "-1";
            $$.type_sizeof = "";
+           ECPGfree_struct_member(struct_member_list[struct_level]);
            struct_member_list[struct_level] = NULL;
        }
    }
@@ -928,6 +932,7 @@ enum_definition: '{' c_list '}'
 
 struct_union_type_with_symbol: s_struct_union_symbol
    {
+       ECPGfree_struct_member(struct_member_list[struct_level]);
        struct_member_list[struct_level++] = NULL;
        if (struct_level >= STRUCT_DEPTH)
            mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition");
@@ -969,12 +974,13 @@ struct_union_type_with_symbol: s_struct_union_symbol
        this->name = mm_strdup(su_type.type_str);
        this->brace_level = braces_open;
        this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
+       this->type->type_storage = NULL;
        this->type->type_enum = su_type.type_enum;
        this->type->type_str = mm_strdup(su_type.type_str);
        this->type->type_dimension = mm_strdup("-1");   /* dimension of array */
        this->type->type_index = mm_strdup("-1");   /* length of string */
-       this->type->type_sizeof = ECPGstruct_sizeof;
-       this->struct_member_list = struct_member_list[struct_level];
+       this->type->type_sizeof = ECPGstruct_sizeof ? mm_strdup(ECPGstruct_sizeof) : NULL;
+       this->struct_member_list = ECPGstruct_member_dup(struct_member_list[struct_level]);
 
        types = this;
        @$ = cat_str(4, su_type.type_str, "{", @4, "}");
@@ -984,6 +990,7 @@ struct_union_type_with_symbol: s_struct_union_symbol
 struct_union_type: struct_union_type_with_symbol
    | s_struct_union
    {
+       ECPGfree_struct_member(struct_member_list[struct_level]);
        struct_member_list[struct_level++] = NULL;
        if (struct_level >= STRUCT_DEPTH)
            mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition");
index 7f52521dbf12aee7ce38123962136ff09f67ae74..9f6dacd2aea550d09d30d5fed572cce590c6228d 100644 (file)
@@ -94,13 +94,14 @@ ECPGmake_array_type(struct ECPGtype *type, const char *size)
 }
 
 struct ECPGtype *
-ECPGmake_struct_type(struct ECPGstruct_member *rm, enum ECPGttype type, char *type_name, char *struct_sizeof)
+ECPGmake_struct_type(struct ECPGstruct_member *rm, enum ECPGttype type,
+                    const char *type_name, const char *struct_sizeof)
 {
    struct ECPGtype *ne = ECPGmake_simple_type(type, "1", 0);
 
    ne->type_name = mm_strdup(type_name);
    ne->u.members = ECPGstruct_member_dup(rm);
-   ne->struct_sizeof = struct_sizeof;
+   ne->struct_sizeof = mm_strdup(struct_sizeof);
 
    return ne;
 }
@@ -622,7 +623,7 @@ ECPGfree_struct_member(struct ECPGstruct_member *rm)
 
        rm = rm->next;
        free(p->name);
-       free(p->type);
+       ECPGfree_type(p->type);
        free(p);
    }
 }
@@ -643,14 +644,13 @@ ECPGfree_type(struct ECPGtype *type)
                    case ECPGt_struct:
                    case ECPGt_union:
                        /* Array of structs. */
-                       ECPGfree_struct_member(type->u.element->u.members);
-                       free(type->u.element);
+                       ECPGfree_type(type->u.element);
                        break;
                    default:
                        if (!IS_SIMPLE_TYPE(type->u.element->type))
                            base_yyerror("internal error: unknown datatype, please report this to <" PACKAGE_BUGREPORT ">");
 
-                       free(type->u.element);
+                       ECPGfree_type(type->u.element);
                }
                break;
            case ECPGt_struct:
@@ -662,6 +662,9 @@ ECPGfree_type(struct ECPGtype *type)
                break;
        }
    }
+   free(type->type_name);
+   free(type->size);
+   free(type->struct_sizeof);
    free(type);
 }
 
index 90126551d19d8afa8f08314a5e60ec181b1fe722..3d99e1703de459dc47bc04c0781e7216d5b79d44 100644 (file)
@@ -38,8 +38,9 @@ void      ECPGmake_struct_member(const char *name, struct ECPGtype *type,
 struct ECPGtype *ECPGmake_simple_type(enum ECPGttype type, const char *size, int counter);
 struct ECPGtype *ECPGmake_array_type(struct ECPGtype *type, const char *size);
 struct ECPGtype *ECPGmake_struct_type(struct ECPGstruct_member *rm,
-                                     enum ECPGttype type, char *type_name,
-                                     char *struct_sizeof);
+                                     enum ECPGttype type,
+                                     const char *type_name,
+                                     const char *struct_sizeof);
 struct ECPGstruct_member *ECPGstruct_member_dup(struct ECPGstruct_member *rm);
 
 /* Frees a type. */
index ac80d2c020997aa7dfee3a85b68924e88d3133e5..e9bdfe56456130f9d407220821331d9849a519b0 100644 (file)
@@ -277,7 +277,12 @@ remove_typedefs(int brace_level)
                prev->next = p->next;
 
            if (p->type->type_enum == ECPGt_struct || p->type->type_enum == ECPGt_union)
-               free(p->struct_member_list);
+               ECPGfree_struct_member(p->struct_member_list);
+           free(p->type->type_storage);
+           free(p->type->type_str);
+           free(p->type->type_dimension);
+           free(p->type->type_index);
+           free(p->type->type_sizeof);
            free(p->type);
            free(p->name);
            free(p);