aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorLibravatar Matt Coffin <mcoffin13@gmail.com>2019-06-11 12:10:17 -0600
committerLibravatar Brian Ashworth <bosrsf04@gmail.com>2019-06-11 14:40:36 -0400
commit2b5bf78fafdf027624ca88e1f703bc9e577f4690 (patch)
treeee24a2a3740563aecfab9fdc922eafebf1527c97 /common
parentAdd docs for new IPC keyboard properties (diff)
downloadsway-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')
-rw-r--r--common/stringop.c56
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
254char *argsep(char **stringp, const char *delim) { 254static 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
266char *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}