[Concept,03/26] boot: pxe: Fix token memory leaks in parser

Message ID 20260110202906.187370-4-sjg@u-boot.org
State New
Headers
Series boot: pxe: Add three-phase API and fix memory leaks |

Commit Message

Simon Glass Jan. 10, 2026, 8:28 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

The get_token() function allocates memory for t.val when parsing
keywords and string literals, but callers do not free this memory.

Fix this by:
- Initialising t.val to NULL in get_token() so free() is safe for
  T_EOL/T_EOF tokens which do not allocate
- Adding free(t.val) calls in parse_menu(), parse_label_menu(),
  parse_label(), and parse_pxefile_top() after token processing

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 boot/pxe_parse.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)
  

Patch

diff --git a/boot/pxe_parse.c b/boot/pxe_parse.c
index 6d148756b0d..8c720db5e75 100644
--- a/boot/pxe_parse.c
+++ b/boot/pxe_parse.c
@@ -232,6 +232,7 @@  static void get_token(char **p, struct token *t, enum lex_state state)
 	char *c = *p;
 
 	t->type = T_INVALID;
+	t->val = NULL;
 
 	/* eat non EOL whitespace */
 	while (isblank(*c))
@@ -418,6 +419,7 @@  static int parse_menu(struct pxe_context *ctx, char **c, struct pxe_menu *cfg,
 	char *s = *c;
 	int err = 0;
 
+	t.val = NULL;
 	get_token(c, &t, L_KEYWORD);
 
 	switch (t.type) {
@@ -434,6 +436,7 @@  static int parse_menu(struct pxe_context *ctx, char **c, struct pxe_menu *cfg,
 		printf("Ignoring malformed menu command: %.*s\n",
 		       (int)(*c - s), s);
 	}
+	free(t.val);
 	if (err < 0)
 		return err;
 
@@ -452,6 +455,7 @@  static int parse_label_menu(char **c, struct pxe_menu *cfg,
 	char *s;
 
 	s = *c;
+	t.val = NULL;
 	get_token(c, &t, L_KEYWORD);
 
 	switch (t.type) {
@@ -471,6 +475,7 @@  static int parse_label_menu(char **c, struct pxe_menu *cfg,
 		       (int)(*c - s), s);
 	}
 
+	free(t.val);
 	eol_or_eof(c);
 
 	return 0;
@@ -534,8 +539,10 @@  static int parse_label(char **c, struct pxe_menu *cfg)
 	}
 	list_add_tail(&label->list, &cfg->labels);
 
+	t.val = NULL;
 	while (1) {
 		s = *c;
+		free(t.val);
 		get_token(c, &t, L_KEYWORD);
 
 		err = 0;
@@ -595,8 +602,10 @@  static int parse_label(char **c, struct pxe_menu *cfg)
 
 			if (p) {
 				label->say = strndup(*c + 1, p - *c - 1);
-				if (!label->say)
+				if (!label->say) {
+					free(t.val);
 					return -ENOMEM;
+				}
 				*c = p;
 			}
 			break;
@@ -608,11 +617,14 @@  static int parse_label(char **c, struct pxe_menu *cfg)
 			 * something for the menu level context to handle.
 			 */
 			*c = s;
+			free(t.val);
 			return 1;
 		}
 
-		if (err < 0)
+		if (err < 0) {
+			free(t.val);
 			return err;
+		}
 	}
 }
 
@@ -637,8 +649,10 @@  int parse_pxefile_top(struct pxe_context *ctx, char *p, ulong base,
 		return -EMLINK;
 	}
 
+	t.val = NULL;
 	while (1) {
 		s = p;
+		free(t.val);
 		get_token(&p, &t, L_KEYWORD);
 
 		err = 0;
@@ -686,6 +700,7 @@  int parse_pxefile_top(struct pxe_context *ctx, char *p, ulong base,
 		case T_EOL:
 			break;
 		case T_EOF:
+			free(t.val);
 			return 1;
 		default:
 			printf("Ignoring unknown command: %.*s\n",
@@ -693,7 +708,9 @@  int parse_pxefile_top(struct pxe_context *ctx, char *p, ulong base,
 			eol_or_eof(&p);
 		}
 
-		if (err < 0)
+		if (err < 0) {
+			free(t.val);
 			return err;
+		}
 	}
 }