diff options
author | Matt Coffin <mcoffin13@gmail.com> | 2019-06-11 12:10:17 -0600 |
---|---|---|
committer | Brian Ashworth <bosrsf04@gmail.com> | 2019-06-11 14:40:36 -0400 |
commit | 2b5bf78fafdf027624ca88e1f703bc9e577f4690 (patch) | |
tree | ee24a2a3740563aecfab9fdc922eafebf1527c97 /common/stringop.c | |
parent | Add docs for new IPC keyboard properties (diff) | |
download | sway-2b5bf78fafdf027624ca88e1f703bc9e577f4690.tar.gz sway-2b5bf78fafdf027624ca88e1f703bc9e577f4690.tar.zst sway-2b5bf78fafdf027624ca88e1f703bc9e577f4690.zip |
Fix segfaults caused by faulty command parsing
This patch fixes faulty command parsing introduced by
f0f5de9a9e87ca1f0d74e7cbf82ffceba51ffbe6. When that commit allowed
criteria reset on ';' delimeters in commands lists, it failed to account
for its inner ','-parsing loop eating threw the entire rest of the
string.
This patch refactors argsep to use a list of multiple separators, and
(optionally) return the separator that it matched against in this
iteration via a pointer. This allows it to hint at the command parser
which separator was used at the end of the last command, allowing it to
trigger a potential secondary read of the criteria.
Fixes #4239
Diffstat (limited to 'common/stringop.c')
-rw-r--r-- | common/stringop.c | 56 |
1 files changed, 40 insertions, 16 deletions
diff --git a/common/stringop.c b/common/stringop.c index dea152cc..ac7df296 100644 --- a/common/stringop.c +++ b/common/stringop.c | |||
@@ -251,37 +251,61 @@ char *join_args(char **argv, int argc) { | |||
251 | return res; | 251 | return res; |
252 | } | 252 | } |
253 | 253 | ||
254 | char *argsep(char **stringp, const char *delim) { | 254 | static inline char *argsep_next_interesting(const char *src, const char *delim) { |
255 | char *special = strpbrk(src, "\"'\\"); | ||
256 | char *next_delim = strpbrk(src, delim); | ||
257 | if (!special) { | ||
258 | return next_delim; | ||
259 | } | ||
260 | if (!next_delim) { | ||
261 | return special; | ||
262 | } | ||
263 | return (next_delim < special) ? next_delim : special; | ||
264 | } | ||
265 | |||
266 | char *argsep(char **stringp, const char *delim, char *matched) { | ||
255 | char *start = *stringp; | 267 | char *start = *stringp; |
256 | char *end = start; | 268 | char *end = start; |
257 | bool in_string = false; | 269 | bool in_string = false; |
258 | bool in_char = false; | 270 | bool in_char = false; |
259 | bool escaped = false; | 271 | bool escaped = false; |
260 | while (1) { | 272 | char *interesting = NULL; |
261 | if (*end == '"' && !in_char && !escaped) { | 273 | |
274 | while ((interesting = argsep_next_interesting(end, delim))) { | ||
275 | if (escaped && interesting != end) { | ||
276 | escaped = false; | ||
277 | } | ||
278 | if (*interesting == '"' && !in_char && !escaped) { | ||
262 | in_string = !in_string; | 279 | in_string = !in_string; |
263 | } else if (*end == '\'' && !in_string && !escaped) { | 280 | end = interesting + 1; |
281 | } else if (*interesting == '\'' && !in_string && !escaped) { | ||
264 | in_char = !in_char; | 282 | in_char = !in_char; |
265 | } else if (*end == '\\') { | 283 | end = interesting + 1; |
284 | } else if (*interesting == '\\') { | ||
266 | escaped = !escaped; | 285 | escaped = !escaped; |
267 | } else if (*end == '\0') { | 286 | end = interesting + 1; |
268 | *stringp = NULL; | 287 | } else if (!in_string && !in_char && !escaped) { |
269 | break; | 288 | // We must have matched a separator |
270 | } else if (!in_string && !in_char && !escaped && strchr(delim, *end)) { | 289 | end = interesting; |
290 | if (matched) { | ||
291 | *matched = *end; | ||
292 | } | ||
271 | if (end - start) { | 293 | if (end - start) { |
272 | *(end++) = 0; | 294 | *(end++) = 0; |
273 | *stringp = end + strspn(end, delim);; | 295 | *stringp = end; |
274 | if (!**stringp) *stringp = NULL; | ||
275 | break; | 296 | break; |
276 | } else { | 297 | } else { |
277 | ++start; | 298 | end = ++start; |
278 | end = start; | ||
279 | } | 299 | } |
300 | } else { | ||
301 | end++; | ||
280 | } | 302 | } |
281 | if (*end != '\\') { | 303 | } |
282 | escaped = false; | 304 | if (!interesting) { |
305 | *stringp = NULL; | ||
306 | if (matched) { | ||
307 | *matched = '\0'; | ||
283 | } | 308 | } |
284 | ++end; | ||
285 | } | 309 | } |
286 | return start; | 310 | return start; |
287 | } | 311 | } |