Index | Thread | Search

From:
Han Boetes <hboetes@gmail.com>
Subject:
leak in mg, interpreter.c:599
To:
tech@openbsd.org
Date:
Sat, 21 Feb 2026 20:33:09 +0100

Download raw body.

Thread
  • Han Boetes:

    leak in mg, interpreter.c:599

While playing around with valgrind and mg I noticed some leaks.
First, I created a test init-file with the contents:

(define myvar "hello")
(define myvar "world")

After which something is leaking in interpreter.c at line 599, see 
valgrind output below.

Upon redefinition of a variable, the old varentry and its v_name string 
are not freed. Additionally, SLIST_INSERT_HEAD is called before strndup 
succeeds, meaning a failed strndup leaves a partially initialised entry 
in the live list.
The following patch fixes both issues. With it applied, the 
interpreter.c leak in the valgrind output below disappears.

--- a/interpreter.c
+++ b/interpreter.c
@@ -592,15 +592,20 @@

      if (!SLIST_EMPTY(&varhead)) {
          SLIST_FOREACH_SAFE(v1, &varhead, entry, vt) {
-            if (strcmp(vnamep, v1->v_name) == 0)
+            if (strcmp(vnamep, v1->v_name) == 0) {
                  SLIST_REMOVE(&varhead, v1, varentry, entry);
+                free(v1->v_name);
+                free(v1);
+            }
          }
      }
      if ((v1 = malloc(sizeof(struct varentry))) == NULL)
          return (ABORT);
-    SLIST_INSERT_HEAD(&varhead, v1, entry);
-    if ((v1->v_name = strndup(vnamep, BUFSIZE)) == NULL)
+    if ((v1->v_name = strndup(vnamep, BUFSIZE)) == NULL) {
+        free(v1);
          return(dobeep_msg("strndup error"));
+    }
+    SLIST_INSERT_HEAD(&varhead, v1, entry);
      vnamep = v1->v_name;
      v1->v_count = 0;
      v1->v_vals = NULL;


%   valgrind --leak-check=full ./mg -u ../test
==132660== Memcheck, a memory error detector
==132660== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==132660== Using Valgrind-3.26.0 and LibVEX; rerun with -h for copyright 
info
==132660== Command: ./mg -u ../test
==132660==
==132660==
==132660== HEAP SUMMARY:
==132660==     in use at exit: 61,787 bytes in 191 blocks
==132660==   total heap usage: 1,176 allocs, 985 frees, 249,547 bytes 
allocated
==132660==
==132660== 8 bytes in 1 blocks are definitely lost in loss record 12 of 96
==132660==    at 0x4840B26: malloc (vg_replace_malloc.c:447)
==132660==    by 0x4096AF: remap (extend.c:143)
==132660==    by 0x40A115: bindkey.constprop.0.isra.0 (extend.c:412)
==132660==    by 0x416E6E: ttykeymapinit (ttykbd.c:39)
==132660==    by 0x400CDA: main (main.c:165)
==132660==
==132660== 16 bytes in 1 blocks are definitely lost in loss record 16 of 96
==132660==    at 0x4848683: calloc (vg_replace_malloc.c:1678)
==132660==    by 0x4098DD: remap (extend.c:125)
==132660==    by 0x40A115: bindkey.constprop.0.isra.0 (extend.c:412)
==132660==    by 0x416E96: ttykeymapinit (ttykbd.c:41)
==132660==    by 0x400CDA: main (main.c:165)
==132660==
==132660== 32 bytes in 1 blocks are definitely lost in loss record 58 of 96
==132660==    at 0x4848683: calloc (vg_replace_malloc.c:1678)
==132660==    by 0x4098DD: remap (extend.c:125)
==132660==    by 0x40A115: bindkey.constprop.0.isra.0 (extend.c:412)
==132660==    by 0x416EBE: ttykeymapinit (ttykbd.c:43)
==132660==    by 0x400CDA: main (main.c:165)
==132660==
==132660== 40 bytes in 1 blocks are definitely lost in loss record 60 of 96
==132660==    at 0x4848683: calloc (vg_replace_malloc.c:1678)
==132660==    by 0x4097A4: remap (extend.c:112)
==132660==    by 0x40A115: bindkey.constprop.0.isra.0 (extend.c:412)
==132660==    by 0x416F12: ttykeymapinit (ttykbd.c:49)
==132660==    by 0x400CDA: main (main.c:165)
==132660==
==132660== 112 bytes in 1 blocks are definitely lost in loss record 74 of 96
==132660==    at 0x4840B26: malloc (vg_replace_malloc.c:447)
==132660==    by 0x4094E2: reallocmap (extend.c:274)
==132660==    by 0x40999F: remap (extend.c:139)
==132660==    by 0x40A0D3: bindkey.constprop.0.isra.0 (extend.c:402)
==132660==    by 0x416F62: ttykeymapinit (ttykbd.c:53)
==132660==    by 0x400CDA: main (main.c:165)
==132660==
==132660== 166 (160 direct, 6 indirect) bytes in 1 blocks are definitely 
lost in loss record 77 of 96
==132660==    at 0x4840B26: malloc (vg_replace_malloc.c:447)
==132660==    by 0x40DCB9: founddef.constprop.0 (interpreter.c:599)
==132660==    by 0x40E4C9: parsdef (interpreter.c:345)
==132660==    by 0x40E4C9: parse.isra.0 (interpreter.c:297)
==132660==    by 0x40E81B: foundparen (interpreter.c:209)
==132660==    by 0x40AD66: load (extend.c:659)
==132660==    by 0x400D05: main (main.c:178)
==132660==
==132660== LEAK SUMMARY:
==132660==    definitely lost: 368 bytes in 6 blocks
==132660==    indirectly lost: 6 bytes in 1 blocks
==132660==      possibly lost: 0 bytes in 0 blocks
==132660==    still reachable: 61,413 bytes in 184 blocks
==132660==         suppressed: 0 bytes in 0 blocks
==132660== Reachable blocks (those to which a pointer was found) are not 
shown.
==132660== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==132660==
==132660== For lists of detected and suppressed errors, rerun with: -s
==132660== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)