From: Tom Lane Date: Wed, 27 Nov 2024 17:41:20 +0000 (-0500) Subject: ecpg: fix some memory leakage of data-type-related structures. X-Git-Tag: REL_18_BETA1~1395 X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=0e6060790d6533847084770845c84e81862bff47;p=postgresql.git ecpg: fix some memory leakage of data-type-related structures. 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 patches 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 leaking 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 --- diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header index a415780faff..e79b6b0de8c 100644 --- a/src/interfaces/ecpg/preproc/ecpg.header +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -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; diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index 424903f76e0..321bcbccac7 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -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"); diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c index 7f52521dbf1..9f6dacd2aea 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -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); } diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h index 90126551d19..3d99e1703de 100644 --- a/src/interfaces/ecpg/preproc/type.h +++ b/src/interfaces/ecpg/preproc/type.h @@ -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. */ diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c index ac80d2c0209..e9bdfe56456 100644 --- a/src/interfaces/ecpg/preproc/variable.c +++ b/src/interfaces/ecpg/preproc/variable.c @@ -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);