yml: don’t crash when (trying to) merge anchors that aren’t dictionaries

Up until now, we only asserted the value being merged in was a
dictionary.

Now we do a proper check and return a real error message instead.

Closes #32
This commit is contained in:
Daniel Eklöf 2021-02-11 19:02:14 +01:00
parent afe22813f3
commit 0855e5ff63
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 44 additions and 9 deletions

View file

@ -13,6 +13,11 @@
### Deprecated ### Deprecated
### Removed ### Removed
### Fixed ### Fixed
* Crash when merging non-dictionary anchors in the YAML configuration
(https://codeberg.org/dnkl/yambar/issues/32).
### Security ### Security
### Contributors ### Contributors

48
yml.c
View file

@ -177,13 +177,14 @@ add_anchor(struct yml_node *root, const char *anchor,
root->root.anchor_count++; root->root.anchor_count++;
} }
static void static bool
post_process(struct yml_node *node) post_process(struct yml_node *node, char **error)
{ {
switch (node->type) { switch (node->type) {
case ROOT: case ROOT:
if (node->root.root != NULL) if (node->root.root != NULL)
post_process(node->root.root); if (!post_process(node->root.root, error))
return false;
break; break;
case SCALAR: case SCALAR:
@ -192,13 +193,17 @@ post_process(struct yml_node *node)
case LIST: case LIST:
tll_foreach(node->list.values, it) tll_foreach(node->list.values, it)
post_process(it->item); if (!post_process(it->item, error))
return false;
break; break;
case DICT: case DICT:
tll_foreach(node->dict.pairs, it) { tll_foreach(node->dict.pairs, it) {
post_process(it->item.key); if (!post_process(it->item.key, error) ||
post_process(it->item.value); !post_process(it->item.value, error))
{
return false;
}
} }
tll_foreach(node->dict.pairs, it) { tll_foreach(node->dict.pairs, it) {
@ -214,7 +219,17 @@ post_process(struct yml_node *node)
* e.g. <<: [*foo, *bar] * e.g. <<: [*foo, *bar]
*/ */
tll_foreach(it->item.value->list.values, v_it) { tll_foreach(it->item.value->list.values, v_it) {
assert(v_it->item->type == DICT); if (v_it->item->type != DICT) {
int cnt = snprintf(
NULL, 0, "%zu:%zu: cannot merge non-dictionary anchor",
v_it->item->line, v_it->item->column);
*error = malloc(cnt + 1);
snprintf(
*error, cnt + 1, "%zu:%zu: cannot merge non-dictionary anchor",
v_it->item->line, v_it->item->column);
return false;
}
tll_foreach(v_it->item->dict.pairs, vv_it) { tll_foreach(v_it->item->dict.pairs, vv_it) {
struct dict_pair p = { struct dict_pair p = {
.key = vv_it->item.key, .key = vv_it->item.key,
@ -240,7 +255,17 @@ post_process(struct yml_node *node)
* Merge value is a dictionary only * Merge value is a dictionary only
* e.g. <<: *foo * e.g. <<: *foo
*/ */
assert(it->item.value->type == DICT); if (it->item.value->type != DICT) {
int cnt = snprintf(
NULL, 0, "%zu:%zu: cannot merge non-dictionary anchor",
it->item.value->line, it->item.value->column);
*error = malloc(cnt + 1);
snprintf(
*error, cnt + 1, "%zu:%zu: cannot merge non-dictionary anchor",
it->item.value->line, it->item.value->column);
return false;
}
tll_foreach(it->item.value->dict.pairs, v_it) { tll_foreach(it->item.value->dict.pairs, v_it) {
struct dict_pair p = { struct dict_pair p = {
.key = v_it->item.key, .key = v_it->item.key,
@ -269,6 +294,8 @@ post_process(struct yml_node *node)
} }
break; break;
} }
return true;
} }
static const char * static const char *
@ -526,7 +553,10 @@ yml_load(FILE *yml, char **error)
yaml_parser_delete(&yaml); yaml_parser_delete(&yaml);
post_process(root); if (!post_process(root, error)) {
yml_destroy(root);
return NULL;
}
return root; return root;
err: err: