From 43f3f423db776695172f74d35322f99b23706b86 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 14 Oct 2024 14:00:40 -0400
Subject: [PATCH v6 1/3] 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.  (Note: the
lifetime of those lists is not obvious.  They are still live after
initial construction, in order to handle cases like

struct foo { ... } foovar1, foovar2;

We can't delete the list immediately after parsing the right brace,
because it needs to be copied for each of the variables.  Instead,
it's kept around until the next struct declaration.)

Discussion: https://postgr.es/m/2011420.1713493114@sss.pgh.pa.us
---
 src/interfaces/ecpg/preproc/ecpg.header  |  3 ++-
 src/interfaces/ecpg/preproc/ecpg.trailer | 11 +++++++++--
 src/interfaces/ecpg/preproc/type.c       | 15 +++++++++------
 src/interfaces/ecpg/preproc/type.h       |  5 +++--
 src/interfaces/ecpg/preproc/variable.c   |  7 ++++++-
 5 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header
index d3df8eabbb..d54eca918d 100644
--- a/src/interfaces/ecpg/preproc/ecpg.header
+++ b/src/interfaces/ecpg/preproc/ecpg.header
@@ -506,11 +506,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 0a77559e83..41029701fc 100644
--- a/src/interfaces/ecpg/preproc/ecpg.trailer
+++ b/src/interfaces/ecpg/preproc/ecpg.trailer
@@ -751,6 +751,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);
 		}
 	}
@@ -878,6 +879,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);
 		}
 	}
@@ -900,6 +902,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
@@ -909,6 +912,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;
 		}
 	}
@@ -924,6 +928,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");
@@ -965,12 +970,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, "}");
@@ -980,6 +986,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 7f52521dbf..9f6dacd2ae 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 90126551d1..3d99e1703d 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 6b87d5ff3d..4831f56cba 100644
--- a/src/interfaces/ecpg/preproc/variable.c
+++ b/src/interfaces/ecpg/preproc/variable.c
@@ -273,7 +273,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);
-- 
2.43.5

