Skip to content

Fix spurious cascading errors on when-false nodes in multi-error validation#2528

Open
szabolcs-szekely wants to merge 3 commits into
CESNET:develfrom
nokia:fix/when-false-xpath-multi-error
Open

Fix spurious cascading errors on when-false nodes in multi-error validation#2528
szabolcs-szekely wants to merge 3 commits into
CESNET:develfrom
nokia:fix/when-false-xpath-multi-error

Conversation

@szabolcs-szekely
Copy link
Copy Markdown

Relates to #2516.
We want to use yanglint's multi-error mode (LYD_VALIDATE_MULTI_ERROR) for testing. Building on the crash fix in ff3cd62, a when-false node was still indistinguishable from a not-yet-evaluated
when: XPath returned LY_EINCOMPLETE for it, and must/leafref/child-when ran against the logically non-existent subtree, producing spurious cascading errors.
Changes:

  • New LYD_WHEN_FALSE flag to mark a when-false node distinctly from a not-yet-evaluated one, cleared again if the when later resolves to true.
  • XPath treats LYD_WHEN_FALSE nodes as non-existent (LY_ENOT) instead of LY_EINCOMPLETE.
  • Validation skips must/obsolete/child/container-default checks for these nodes and removes their descendants from node_types/node_when.
  • Regression tests for the when/must cross-reference (incl. keyed-list hash lookup), the leafref-inside-when-false-container case, and a nested when-in-when case.

…errors

Mark when-false nodes with a new LYD_WHEN_FALSE flag so XPath evaluation
treats them as non-existent (LY_ENOT) instead of incomplete
(LY_EINCOMPLETE). This prevents the internal-error crash in
lyd_validate_dummy_when and spurious cascading errors on must, leafref,
and child when expressions under LYD_VALIDATE_MULTI_ERROR.

Clean up node_types and node_when entries for descendants of a
when-false node so leafref validation and child when evaluations do not
run against a logically non-existent subtree.

Add regression tests covering the when/must cross-reference scenario
and the leafref-inside-when-false-container case.

Fixes CESNET#2516
Add a fourth sub-case to test_when_must_cross_ref that places the
when-false node on a list with a key and references it through a
[key='...'] predicate in a sibling must constraint. This routes the
XPath step through moveto_node_hash_child rather than
moveto_node_check, exercising the second LYD_WHEN_FALSE branch in
src/xpath.c explicitly.

The data deliberately sets item[name='a']/value to 'expected' so that
a regression in the hash-lookup branch would cause the must to pass
silently. Both the when error and the must failure must be reported.

Fixes CESNET#2516
Address review findings on the LYD_WHEN_FALSE handling.

- Initialize the return code before skipping a when-false node in
  lyd_validate_final_r so a when-false first sibling no longer reads an
  uninitialized value.
- Clear a stale LYD_WHEN_FALSE mark when a when later resolves to true so
  XPath no longer treats a now-valid node as non-existent on revalidation.
- Skip container default handling for when-false nodes in addition to
  their child validation.
- Add a nested when-in-when regression test confirming the node_when
  descendant cleanup suppresses the spurious child when error.
Copy link
Copy Markdown
Member

@michalvasko michalvasko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I suppose, since it does not add too much code. But like I said before, this feature was added later and the original design did not anticipate it so it is expected it does not work perfectly. For a proper implementation, the validation would need significant refactoring, which seems not worth it.

Comment thread src/validation.c
Comment on lines +439 to +476
/* invalid data; mark the when as resolved-to-false so subsequent XPath
* evaluations on this node return "no match" instead of LY_EINCOMPLETE */
node->flags |= LYD_WHEN_FALSE;
/* remove descendants from node_types so their leafrefs are not validated
* against the when-false subtree, which would produce spurious cascading
* errors (mirrors the cleanup done by lyd_validate_autodel_node_del) */
if (node_types && node_types->count) {
struct lyd_node *iter;
uint32_t idx;

LYD_TREE_DFS_BEGIN(node, iter) {
if ((iter->schema->nodetype & LYD_NODE_TERM) &&
LYSC_GET_TYPE_PLG(((struct lysc_node_leaf *)iter->schema)->type->plugin_ref)->validate_tree &&
ly_set_contains(node_types, iter, &idx)) {
ly_set_rm_index(node_types, idx, NULL);
}
LYD_TREE_DFS_END(node, iter);
}
}
/* remove descendants from node_when so their own when conditions are not
* evaluated; a when-false subtree is logically non-existent, so child
* whens are moot and would otherwise produce spurious cascading errors */
if (node_when->count > 1) {
struct lyd_node *iter;
uint32_t idx;

count = node_when->count;
LYD_TREE_DFS_BEGIN(node, iter) {
if ((iter != node) && ly_set_contains(node_when, iter, &idx)) {
ly_set_rm_index_ordered(node_when, idx, NULL);
}
LYD_TREE_DFS_END(node, iter);
}
if (count > node_when->count) {
/* descendants were removed, refresh the iteration index */
ly_set_contains(node_when, node, &i);
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this code, the function is too long, please put this into a separate function. Also, it may impact performance so why not use the new flag LYD_WHEN_FALSE only for LYD_VALIDATE_MULTI_ERROR validation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants