yml: fix crash when referencing a nonn-existent anchor

This commit is contained in:
Daniel Eklöf 2020-01-15 11:03:40 +01:00
parent 74043d0e6d
commit 1a7b00054f
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

45
yml.c
View file

@ -12,6 +12,7 @@
enum yml_error { enum yml_error {
YML_ERR_NONE, YML_ERR_NONE,
YML_ERR_DUPLICATE_KEY, YML_ERR_DUPLICATE_KEY,
YML_ERR_INVALID_ANCHOR,
YML_ERR_UNKNOWN, YML_ERR_UNKNOWN,
}; };
@ -273,7 +274,8 @@ post_process(struct yml_node *node)
static const char * static const char *
format_error(enum yml_error err, format_error(enum yml_error err,
const struct yml_node *parent, const struct yml_node *parent,
const struct yml_node *node) const struct yml_node *node,
const char *anchor)
{ {
static char err_str[512]; static char err_str[512];
@ -314,6 +316,26 @@ format_error(enum yml_error err,
break; break;
} }
case YML_ERR_INVALID_ANCHOR:
if (parent->parent != NULL && parent->parent->type == DICT) {
tll_foreach(parent->parent->dict.pairs, pair) {
if (pair->item.value != parent)
continue;
if (pair->item.key->type != SCALAR)
break;
snprintf(err_str, sizeof(err_str),
"%s: invalid anchor: %s",
pair->item.key->scalar.value,
anchor != NULL ? anchor : "<unknown>");
return err_str;
}
}
snprintf(err_str, sizeof(err_str), "invalid anchor: %s",
anchor != NULL ? anchor : "<unknown>");
break;
case YML_ERR_UNKNOWN: case YML_ERR_UNKNOWN:
snprintf(err_str, sizeof(err_str), "unknown error"); snprintf(err_str, sizeof(err_str), "unknown error");
break; break;
@ -385,7 +407,8 @@ yml_load(FILE *yml, char **error)
indent -= 2; indent -= 2;
break; break;
case YAML_ALIAS_EVENT: case YAML_ALIAS_EVENT: {
bool got_match = false;
for (size_t i = 0; i < root->root.anchor_count; i++) { for (size_t i = 0; i < root->root.anchor_count; i++) {
const struct anchor_map *map = &root->root.anchors[i]; const struct anchor_map *map = &root->root.anchors[i];
@ -397,14 +420,23 @@ yml_load(FILE *yml, char **error)
enum yml_error err = add_node(n, clone, event.start_mark); enum yml_error err = add_node(n, clone, event.start_mark);
if (err != YML_ERR_NONE) { if (err != YML_ERR_NONE) {
error_str = format_error(err, n, clone); error_str = format_error(err, n, clone, NULL);
yml_destroy(clone); yml_destroy(clone);
goto err; goto err;
} }
got_match = true;
break; break;
} }
if (!got_match) {
error_str = format_error(
YML_ERR_INVALID_ANCHOR, n, NULL,
(const char *)event.data.alias.anchor);
goto err;
}
break; break;
}
case YAML_SCALAR_EVENT: { case YAML_SCALAR_EVENT: {
struct yml_node *new_scalar = calloc(1, sizeof(*new_scalar)); struct yml_node *new_scalar = calloc(1, sizeof(*new_scalar));
@ -414,7 +446,7 @@ yml_load(FILE *yml, char **error)
enum yml_error err = add_node(n, new_scalar, event.start_mark); enum yml_error err = add_node(n, new_scalar, event.start_mark);
if (err != YML_ERR_NONE) { if (err != YML_ERR_NONE) {
error_str = format_error(err, n, new_scalar); error_str = format_error(err, n, new_scalar, NULL);
yml_destroy(new_scalar); yml_destroy(new_scalar);
goto err; goto err;
} }
@ -434,7 +466,7 @@ yml_load(FILE *yml, char **error)
enum yml_error err = add_node(n, new_list, event.start_mark); enum yml_error err = add_node(n, new_list, event.start_mark);
if (err != YML_ERR_NONE) { if (err != YML_ERR_NONE) {
error_str = format_error(err, n, new_list); error_str = format_error(err, n, new_list, NULL);
yml_destroy(new_list); yml_destroy(new_list);
goto err; goto err;
} }
@ -462,7 +494,7 @@ yml_load(FILE *yml, char **error)
enum yml_error err = add_node(n, new_dict, event.start_mark); enum yml_error err = add_node(n, new_dict, event.start_mark);
if (err != YML_ERR_NONE) { if (err != YML_ERR_NONE) {
error_str = format_error(err, n, new_dict); error_str = format_error(err, n, new_dict, NULL);
yml_destroy(new_dict); yml_destroy(new_dict);
goto err; goto err;
} }
@ -477,6 +509,7 @@ yml_load(FILE *yml, char **error)
} }
case YAML_MAPPING_END_EVENT: case YAML_MAPPING_END_EVENT:
assert(!n->dict.next_is_value);
indent -= 2; indent -= 2;
assert(n->parent != NULL); assert(n->parent != NULL);
n = n->parent; n = n->parent;