Skip to content

Commit a3ca4b9

Browse files
committed
resolve BUGFIX remove invalid restriction of intid keys order
They had to be ordered previously, that is no longer true because RFC does not specify such requirement anywhere. Fixes #360
1 parent f39be7a commit a3ca4b9

6 files changed

Lines changed: 178 additions & 111 deletions

File tree

src/resolve.c

Lines changed: 136 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -3910,142 +3910,160 @@ resolve_schema_leafref(const char *path, struct lys_node *parent, const struct l
39103910
*
39113911
* @param[in] prev_mod Previous module to use in case there is no prefix.
39123912
* @param[in] pred Predicate to use.
3913-
* @param[in,out] node_match Nodes matching the restriction without
3914-
* the predicate. Nodes not satisfying
3915-
* the predicate are removed.
3913+
* @param[in,out] node Node matching the restriction without
3914+
* the predicate. If it does not satisfy the predicate,
3915+
* it is set to NULL.
39163916
*
39173917
* @return Number of characters successfully parsed,
39183918
* positive on success, negative on failure.
39193919
*/
39203920
static int
3921-
resolve_instid_predicate(const struct lys_module *prev_mod, const char *pred, struct unres_data *node_match)
3921+
resolve_instid_predicate(const struct lys_module *prev_mod, const char *pred, struct lyd_node **node, int cur_idx)
39223922
{
3923-
/* ... /node[target = value] ... */
3924-
struct lyd_node *target;
3923+
/* ... /node[key=value] ... */
3924+
struct lyd_node_leaf_list *key;
3925+
struct lys_node_leaf **list_keys = NULL;
3926+
struct lys_node_list *slist;
39253927
const char *model, *name, *value;
3926-
int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
3927-
uint32_t j;
3928+
int mod_len, nam_len, val_len, i, has_predicate, parsed;
39283929

3929-
assert(pred && node_match->count);
3930+
assert(pred && node && *node);
39303931

3931-
idx = -1;
39323932
parsed = 0;
3933-
3934-
pred_iter = -1;
39353933
do {
3936-
if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
3937-
return -parsed+i;
3934+
if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
3935+
return -parsed + i;
39383936
}
39393937
parsed += i;
3940-
pred += i;
39413938

3942-
if (isdigit(name[0])) {
3943-
/* pos */
3944-
assert(!value);
3945-
idx = atoi(name);
3946-
} else if (name[0] != '.') {
3947-
/* list keys */
3948-
if (pred_iter < 0) {
3949-
pred_iter = 1;
3950-
} else {
3951-
++pred_iter;
3939+
/* target */
3940+
if (name[0] == '.') {
3941+
/* leaf-list value */
3942+
if ((*node)->schema->nodetype != LYS_LEAFLIST) {
3943+
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
3944+
strnodetype((*node)->schema->nodetype), (*node)->schema->name);
3945+
parsed = -1;
3946+
goto cleanup;
39523947
}
3953-
}
39543948

3955-
for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
3956-
/* target */
3957-
if (name[0] == '.') {
3958-
/* leaf-list value */
3959-
if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
3960-
goto remove_instid;
3961-
}
3949+
/* check the value */
3950+
if (strncmp(((struct lyd_node_leaf_list *)*node)->value_str, value, val_len)
3951+
|| ((struct lyd_node_leaf_list *)*node)->value_str[val_len]) {
3952+
*node = NULL;
3953+
goto cleanup;
3954+
}
39623955

3963-
target = node_match->node[j];
3964-
/* check the value */
3965-
if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3966-
|| ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3967-
goto remove_instid;
3968-
}
3956+
} else if (isdigit(name[0])) {
3957+
assert(!value);
39693958

3970-
} else if (!value) {
3971-
/* keyless list position */
3972-
if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3973-
|| ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3974-
goto remove_instid;
3975-
}
3959+
/* keyless list position */
3960+
if ((*node)->schema->nodetype != LYS_LIST) {
3961+
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
3962+
strnodetype((*node)->schema->nodetype), (*node)->schema->name);
3963+
parsed = -1;
3964+
goto cleanup;
3965+
}
39763966

3977-
if (idx != cur_idx) {
3978-
goto remove_instid;
3979-
}
3967+
if (((struct lys_node_list *)(*node)->schema)->keys) {
3968+
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list without keys, but have list \"%s\".",
3969+
(*node)->schema->name);
3970+
parsed = -1;
3971+
goto cleanup;
3972+
}
39803973

3981-
} else {
3982-
/* list key value */
3983-
if (node_match->node[j]->schema->nodetype != LYS_LIST) {
3984-
goto remove_instid;
3985-
}
3974+
/* check the index */
3975+
if (atoi(name) != cur_idx) {
3976+
*node = NULL;
3977+
goto cleanup;
3978+
}
39863979

3987-
/* find the key leaf */
3988-
for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
3989-
if (!target) {
3990-
goto remove_instid;
3991-
}
3992-
if ((struct lys_node_leaf *)target->schema !=
3993-
((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3994-
goto remove_instid;
3980+
} else {
3981+
/* list key value */
3982+
if ((*node)->schema->nodetype != LYS_LIST) {
3983+
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
3984+
strnodetype((*node)->schema->nodetype), (*node)->schema->name);
3985+
parsed = -1;
3986+
goto cleanup;
3987+
}
3988+
slist = (struct lys_node_list *)(*node)->schema;
3989+
3990+
/* prepare key array */
3991+
if (!list_keys) {
3992+
list_keys = malloc(slist->keys_size * sizeof *list_keys);
3993+
LY_CHECK_ERR_RETURN(!list_keys, LOGMEM, -1);
3994+
for (i = 0; i < slist->keys_size; ++i) {
3995+
list_keys[i] = slist->keys[i];
39953996
}
3997+
}
39963998

3997-
/* check name */
3998-
if (strncmp(target->schema->name, name, nam_len) || target->schema->name[nam_len]) {
3999-
goto remove_instid;
3999+
/* find the schema key leaf */
4000+
for (i = 0; i < slist->keys_size; ++i) {
4001+
if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
4002+
break;
40004003
}
4004+
}
4005+
if (i == slist->keys_size) {
4006+
/* this list has no such key */
4007+
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
4008+
" but list \"%s\" does not define it.", nam_len, name, slist->name);
4009+
parsed = -1;
4010+
goto cleanup;
4011+
}
40014012

4002-
/* check module */
4003-
if (model) {
4004-
if (strncmp(target->schema->module->name, model, mod_len)
4005-
|| target->schema->module->name[mod_len]) {
4006-
goto remove_instid;
4007-
}
4008-
} else {
4009-
if (target->schema->module != prev_mod) {
4010-
goto remove_instid;
4011-
}
4013+
/* check module */
4014+
if (model) {
4015+
if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
4016+
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%.*s\", not \"%s\".",
4017+
list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
4018+
parsed = -1;
4019+
goto cleanup;
4020+
}
4021+
} else {
4022+
if (list_keys[i]->module != prev_mod) {
4023+
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%s\", not \"%s\".",
4024+
list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
4025+
parsed = -1;
4026+
goto cleanup;
40124027
}
4028+
}
40134029

4014-
/* check the value */
4015-
if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4016-
|| ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4017-
goto remove_instid;
4030+
/* find the actual data key */
4031+
for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
4032+
if (key->schema == (struct lys_node *)list_keys[i]) {
4033+
break;
40184034
}
40194035
}
4036+
if (!key) {
4037+
/* list instance is missing a key? definitely should not happen */
4038+
LOGINT;
4039+
parsed = -1;
4040+
goto cleanup;
4041+
}
40204042

4021-
/* instid is ok, continue check with the next one */
4022-
++j;
4023-
continue;
4043+
/* check the value */
4044+
if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
4045+
*node = NULL;
4046+
goto cleanup;
4047+
}
40244048

4025-
remove_instid:
4026-
/* does not fulfill conditions, remove instid record */
4027-
unres_data_del(node_match, j);
4049+
/* everything is fine, mark this key as resolved */
4050+
list_keys[i] = NULL;
40284051
}
40294052
} while (has_predicate);
40304053

40314054
/* check that all list keys were specified */
4032-
if ((pred_iter > 0) && node_match->count) {
4033-
j = 0;
4034-
while (j < node_match->count) {
4035-
assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4036-
if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4037-
/* not enough predicates, just remove the list instance */
4038-
unres_data_del(node_match, j);
4039-
} else {
4040-
++j;
4055+
if (list_keys) {
4056+
for (i = 0; i < slist->keys_size; ++i) {
4057+
if (list_keys[i]) {
4058+
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list key \"%s\".", list_keys[i]->name);
4059+
parsed = -1;
4060+
goto cleanup;
40414061
}
40424062
}
4043-
4044-
if (!node_match->count) {
4045-
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4046-
}
40474063
}
40484064

4065+
cleanup:
4066+
free(list_keys);
40494067
return parsed;
40504068
}
40514069

@@ -7260,10 +7278,10 @@ check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
72607278
static int
72617279
resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
72627280
{
7263-
int i = 0, j;
7281+
int i = 0, j, parsed, cur_idx;
72647282
const struct lys_module *mod, *prev_mod = NULL;
72657283
struct ly_ctx *ctx = data->schema->module->ctx;
7266-
struct lyd_node *root;
7284+
struct lyd_node *root, *node;
72677285
const char *model, *name;
72687286
char *str;
72697287
int mod_len, name_len, has_predicate;
@@ -7323,17 +7341,27 @@ resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd
73237341

73247342
if (has_predicate) {
73257343
/* we have predicate, so the current results must be list or leaf-list */
7326-
j = resolve_instid_predicate(mod, &path[i], &node_match);
7327-
if (j < 1) {
7328-
LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
7329-
goto error;
7330-
}
7331-
i += j;
7344+
j = 0;
7345+
/* index of the current node (for lists with position predicates) */
7346+
cur_idx = 1;
7347+
while (j < (signed)node_match.count) {
7348+
node = node_match.node[j];
7349+
parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
7350+
if (parsed < 1) {
7351+
LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
7352+
goto error;
7353+
}
73327354

7333-
if (!node_match.count) {
7334-
/* no instance exists */
7335-
break;
7355+
if (!node) {
7356+
/* current node does not satisfy the predicate */
7357+
unres_data_del(&node_match, j);
7358+
} else {
7359+
++j;
7360+
}
7361+
++cur_idx;
73367362
}
7363+
7364+
i += parsed;
73377365
} else if (node_match.count) {
73387366
/* check that we are not addressing lists */
73397367
for (j = 0; (unsigned)j < node_match.count; ++j) {

tests/data/files/all-data.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"leaf13": "aGVsbG8h",
1616
"leaf14": "ident2",
1717
"leaf15": [null],
18-
"leaf16": "/all:cont1/all:leaf2",
18+
"leaf16": "/all:cont1/leaf2",
1919
"leaf17": "ident2",
2020
"list1": [
2121
{
@@ -34,6 +34,13 @@
3434
"aaa",
3535
"aaaa",
3636
"aaaaaaaaa"
37-
]
37+
],
38+
"list2": [
39+
{
40+
"leaf27": 3,
41+
"leaf28": 4
42+
}
43+
],
44+
"leaf29": "/all:cont1/list2[leaf28='4'][leaf27='3']"
3845
}
3946
}

tests/data/files/all-data.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,9 @@
3333
<llist1>aaa</llist1>
3434
<llist1>aaaa</llist1>
3535
<llist1>aaaaaaaaa</llist1>
36+
<list2>
37+
<leaf27>3</leaf27>
38+
<leaf28>4</leaf28>
39+
</list2>
40+
<leaf29 xmlns:all_mod="urn:all">/all_mod:cont1/all_mod:list2[all_mod:leaf28='4'][all_mod:leaf27='3']</leaf29>
3641
</cont1>

tests/data/files/all.yang

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,21 @@ module all {
199199
ordered-by user;
200200
}
201201

202+
list list2 {
203+
key "leaf27 leaf28";
204+
leaf leaf27 {
205+
type uint8;
206+
}
207+
208+
leaf leaf28 {
209+
type uint8;
210+
}
211+
}
212+
213+
leaf leaf29 {
214+
type instance-identifier;
215+
}
216+
202217
leaf leaf23 {
203218
type empty;
204219
}

tests/data/files/all.yin

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,18 @@
175175
<type name="tdef1"/>
176176
<ordered-by value="user"/>
177177
</leaf-list>
178+
<list name="list2">
179+
<key value="leaf27 leaf28"/>
180+
<leaf name="leaf27">
181+
<type name="uint8"/>
182+
</leaf>
183+
<leaf name="leaf28">
184+
<type name="uint8"/>
185+
</leaf>
186+
</list>
187+
<leaf name="leaf29">
188+
<type name="instance-identifier"/>
189+
</leaf>
178190
<leaf name="leaf23">
179191
<type name="empty"/>
180192
</leaf>

tests/data/test_parse_print.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ test_parse_print_xml(void **state)
227227
assert_int_equal(read(fd, st->str1, s.st_size), s.st_size);
228228
st->str1[s.st_size] = '\0';
229229

230-
st->dt = lyd_parse_path(st->ctx, data, LYD_XML, LYD_OPT_CONFIG);
230+
st->dt = lyd_parse_path(st->ctx, data, LYD_XML, LYD_OPT_CONFIG | LYD_OPT_STRICT);
231231
assert_ptr_not_equal(st->dt, NULL);
232232
lyd_print_mem(&(st->str2), st->dt, LYD_XML, LYP_FORMAT);
233233

0 commit comments

Comments
 (0)