jcs's openbsd hax
openbsd

1. Do not put ASCII_HYPH (0x1c) into the tag file. That happened when tagging a string containing '-' on an input text line, most commonly in man(7) .TP next line scope. 2. Do not let "\-" end the tag. In both cases, translate ASCII_HYPH and "\-" to plain '-' for output. For example, this improves handling of unbound.conf(5).

These two bugs were found thanks to a posting by weerd@.

schwarze 2b14f697 890f3f8e

+48 -15
+1 -1
regress/usr.bin/mandoc/mdoc/Cm/tag.out_html
··· 7 7 <dd>text</dd> 8 8 <dt id="hyphen"><a class="permalink" href="#hyphen"><code class="Cm">-hyphen</code></a></dt> 9 9 <dd>text</dd> 10 - <dt id="minus"><a class="permalink" href="#minus"><code class="Cm">-minus-sign</code></a></dt> 10 + <dt id="minus-sign"><a class="permalink" href="#minus-sign"><code class="Cm">-minus-sign</code></a></dt> 11 11 <dd>text</dd> 12 12 <dt id="backslash"><a class="permalink" href="#backslash"><code class="Cm">\backslash</code></a></dt> 13 13 <dd>text</dd>
+1 -1
regress/usr.bin/mandoc/mdoc/Cm/tag.out_tag
··· 4 4 two tag.mandoc_ascii 9 5 5 three tag.mandoc_ascii 12 6 6 hyphen tag.mandoc_ascii 14 7 - minus tag.mandoc_ascii 17 7 + minus-sign tag.mandoc_ascii 17 8 8 backslash tag.mandoc_ascii 20 9 9 four tag.mandoc_ascii 22
+46 -13
usr.bin/mandoc/tag.c
··· 1 - /* $OpenBSD: tag.c,v 1.37 2022/04/26 11:28:35 schwarze Exp $ */ 1 + /* $OpenBSD: tag.c,v 1.38 2023/11/24 04:48:02 schwarze Exp $ */ 2 2 /* 3 - * Copyright (c) 2015, 2016, 2018, 2019, 2020, 2022 3 + * Copyright (c) 2015, 2016, 2018, 2019, 2020, 2022, 2023 4 4 * Ingo Schwarze <schwarze@openbsd.org> 5 5 * 6 6 * Permission to use, copy, modify, and distribute this software for any ··· 24 24 #include <limits.h> 25 25 #include <stddef.h> 26 26 #include <stdint.h> 27 + #include <stdio.h> 27 28 #include <stdlib.h> 28 29 #include <string.h> 29 30 30 31 #include "mandoc_aux.h" 31 32 #include "mandoc_ohash.h" 33 + #include "mandoc.h" 32 34 #include "roff.h" 33 35 #include "mdoc.h" 34 36 #include "roff_int.h" ··· 86 88 { 87 89 struct tag_entry *entry; 88 90 struct roff_node *nold; 89 - const char *se; 91 + const char *se, *src; 92 + char *cpy; 90 93 size_t len; 91 94 unsigned int slot; 95 + int changed; 92 96 93 97 assert(prio <= TAG_FALLBACK); 94 98 ··· 104 108 105 109 /* Determine the implicit tag. */ 106 110 111 + changed = 1; 107 112 if (s == NULL) { 108 113 if (n->child == NULL || n->child->type != ROFFT_TEXT) 109 114 return; ··· 120 125 s += 2; 121 126 break; 122 127 default: 123 - break; 128 + return; 124 129 } 125 130 break; 126 131 default: 132 + changed = 0; 127 133 break; 128 134 } 129 135 } 130 136 131 137 /* 138 + * Translate \- and ASCII_HYPH to plain '-'. 132 139 * Skip whitespace and escapes and whatever follows, 133 140 * and if there is any, downgrade the priority. 134 141 */ 135 142 136 - len = strcspn(s, " \t\\"); 143 + cpy = mandoc_malloc(strlen(s) + 1); 144 + for (src = s, len = 0; *src != '\0'; src++, len++) { 145 + switch (*src) { 146 + case '\t': 147 + case ' ': 148 + changed = 1; 149 + break; 150 + case ASCII_HYPH: 151 + cpy[len] = '-'; 152 + changed = 1; 153 + continue; 154 + case '\\': 155 + if (src[1] != '-') 156 + break; 157 + src++; 158 + changed = 1; 159 + /* FALLTHROUGH */ 160 + default: 161 + cpy[len] = *src; 162 + continue; 163 + } 164 + break; 165 + } 137 166 if (len == 0) 138 - return; 167 + goto out; 168 + cpy[len] = '\0'; 139 169 140 - se = s + len; 141 - if (*se != '\0' && prio < TAG_WEAK) 170 + if (*src != '\0' && prio < TAG_WEAK) 142 171 prio = TAG_WEAK; 143 172 173 + s = cpy; 174 + se = cpy + len; 144 175 slot = ohash_qlookupi(&tag_data, s, &se); 145 176 entry = ohash_find(&tag_data, slot); 146 177 ··· 148 179 149 180 if (entry == NULL) { 150 181 entry = mandoc_malloc(sizeof(*entry) + len + 1); 151 - memcpy(entry->s, s, len); 152 - entry->s[len] = '\0'; 182 + memcpy(entry->s, s, len + 1); 153 183 entry->nodes = NULL; 154 184 entry->maxnodes = entry->nnodes = 0; 155 185 ohash_insert(&tag_data, slot, entry); ··· 161 191 */ 162 192 163 193 else if (entry->prio < prio) 164 - return; 194 + goto out; 165 195 166 196 /* 167 197 * If the existing entry is worse, clear it. ··· 178 208 } 179 209 if (prio == TAG_FALLBACK) { 180 210 entry->prio = TAG_DELETE; 181 - return; 211 + goto out; 182 212 } 183 213 } 184 214 ··· 192 222 entry->nodes[entry->nnodes++] = n; 193 223 entry->prio = prio; 194 224 n->flags |= NODE_ID; 195 - if (n->child == NULL || n->child->string != s || *se != '\0') { 225 + if (changed) { 196 226 assert(n->tag == NULL); 197 227 n->tag = mandoc_strndup(s, len); 198 228 } 229 + 230 + out: 231 + free(cpy); 199 232 } 200 233 201 234 int