4e33b15085b7cd23fe95256b9d2e9911751aa598
braney
  Sat Sep 26 12:12:04 2026 -0700
lib tests: htmlEncode and attributeEncode on NULL, and the tag strippers on labels with no tags, refs #38226, #37617

Runs under the careful allocator, whose marker straight after each block makes a missing
terminator show up on every run.

diff --git src/lib/tests/htmlEncodeTest.c src/lib/tests/htmlEncodeTest.c
new file mode 100644
index 00000000000..90664f681b5
--- /dev/null
+++ src/lib/tests/htmlEncodeTest.c
@@ -0,0 +1,71 @@
+/* htmlEncodeTest - check the html encoders and tag strippers on edge-case input.
+ *
+ * htmlEncode and attributeEncode are called on item names and tooltips, and some items
+ * have no name, so they must return an empty string for a NULL input.  refs #38226
+ *
+ * htmlTextStripTags and htmlTextStripJavascriptCssAndTags must return a terminated string.
+ * They relied on zeroed memory past the text and allocated no byte for it, so a label with
+ * no tags in it read whatever followed the allocation.  The careful allocator puts a marker
+ * straight after every block, so under it that mistake shows up on every run instead of
+ * only sometimes.  refs #37617 */
+
+/* Copyright (C) 2026 The Regents of the University of California
+ * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
+
+#include "common.h"
+#include "memalloc.h"
+#include "htmshell.h"
+
+static void showEncode(char *label, char *(*encode)(char *s), char *s)
+/* Print what one encoder makes of s. */
+{
+char *out = encode(s);
+printf("  %-16s %-12s -> ", label, (s == NULL) ? "NULL" : ((*s == 0) ? "(empty)" : s));
+if (out == NULL)
+    printf("NULL\n");
+else
+    printf("\"%s\" (%d chars)\n", out, (int)strlen(out));
+freeMem(out);
+}
+
+static void showStrip(char *label, char *(*strip)(char *s), char *s)
+/* Print what one tag stripper makes of s, with its length, so trailing bytes show. */
+{
+char *out = strip(s);
+printf("  %-12s %-40s -> ", label, (s == NULL) ? "NULL" : ((*s == 0) ? "(empty)" : s));
+if (out == NULL)
+    printf("NULL\n");
+else
+    printf("\"%s\" (%d chars)\n", out, (int)strlen(out));
+freeMem(out);
+}
+
+int main(int argc, char *argv[])
+{
+pushCarefulMemHandler(100000000);
+
+printf("encoders\n");
+showEncode("htmlEncode", htmlEncode, NULL);
+showEncode("htmlEncode", htmlEncode, "");
+showEncode("htmlEncode", htmlEncode, "a<b>&'\"");
+showEncode("attributeEncode", attributeEncode, NULL);
+showEncode("attributeEncode", attributeEncode, "");
+showEncode("attributeEncode", attributeEncode, "a b'c");
+
+printf("\ntag strippers\n");
+char *inputs[] = {"plain label", "x", "<b>bold</b> label", "<i>all tag</i>",
+                  "unclosed <b", "a<script>x()</script>b", "a<style>p{}</style>b"};
+int i;
+for (i = 0; i < ArraySize(inputs); i++)
+    showStrip("tags", htmlTextStripTags, inputs[i]);
+for (i = 0; i < ArraySize(inputs); i++)
+    showStrip("js+css+tags", htmlTextStripJavascriptCssAndTags, inputs[i]);
+showStrip("tags", htmlTextStripTags, "");
+showStrip("js+css+tags", htmlTextStripJavascriptCssAndTags, "");
+showStrip("tags", htmlTextStripTags, NULL);
+showStrip("js+css+tags", htmlTextStripJavascriptCssAndTags, NULL);
+
+carefulCheckHeap();
+printf("\nheap markers intact\n");
+return 0;
+}