Skip to content

xpath BUGFIX value functions on nodes without schema - #2612

Merged
michalvasko merged 1 commit into
CESNET:develfrom
lamestllama:fix/opaque-dummy-xpath-functions
Nov 3, 2026
Merged

michalvasko merged 1 commit into
CESNET:develfrom
lamestllama:fix/opaque-dummy-xpath-functions

Conversation

@lamestllama

Copy link
Copy Markdown

What

enum-value(), bit-is-set() and deref() now check that the first node of their node-set argument is an element with a schema node before reading its schema and value. Any other first node has no value, so:

  • enum-value() returns NaN (RFC 7950, section 10.5.1: "If the first node in "nodes" is not of type "enumeration", it returns NaN"),
  • bit-is-set() returns false (section 10.6.1),
  • deref() returns an empty node-set.

derived-from() and derived-from-or-self() already skip such nodes (if (!sleaf || !(sleaf->nodetype & LYD_NODE_TERM)) in xpath_derived_()), and the three functions now behave the same way.

Why

lyd_validate_dummy_when() evaluates the when of a missing node on an opaque dummy node created by lyd_new_opaq(), whose schema is NULL. The three functions dereferenced that NULL schema, so validating a schema such as this one crashed, even on empty input:

leaf v {
  when "enum-value(.) = 1";
  type enumeration {
    enum x;
    enum y;
  }
  mandatory true;
}

RFC 7950, section 7.21.5, gives the dummy node no value: "replacing all instances of the data node for which the "when" statement is defined with a single dummy node with the same name, but with no value and no children. If no such instance exists, the dummy node is tentatively created." Treating it as a node without a value is therefore the specified result, not only a way to avoid the crash.

The same missing check also crashed on the root node, which is stored in the set with a NULL node: for example must "enum-value(/) = 1", bit-is-set(/, 'f') or deref(/). The type check covers this case too. A metadata node is no longer read as if it were a data node; like the root node and an opaque node, it now gives no value to these three functions. A text node (text()) is skipped as well, as xpath_derived_() already does; before, these three functions read the value of its parent element.

Fixes #2604

Test

test_no_value in tests/utests/basic/test_xpath.c:

  • four presence containers each hold a missing mandatory leaf whose when is true only if the function finds no value (string(enum-value(.)) = 'NaN', not(bit-is-set(., 'f')), not(deref(.)), not(derived-from-or-self(., 'c:one'))); each container alone is refused with Mandatory node "v" instance does not exist., which shows that the dummy node is read as having no value;
  • lyd_eval_xpath() on a small tree checks string(enum-value(/)) = 'NaN' (true), bit-is-set(/, 'f') (false) and deref(/) (false).

Before the fix, utest_xpath stops at test_no_value with a segmentation fault (16 of 17 tests pass). After the fix, all 17 pass, utest_validation passes (22 of 22), and the whole ctest run passes (69 of 69; Debug build, GCC 13.3, aarch64).

enum-value(), bit-is-set() and deref() read the schema of the first
argument node without checking it, so they crashed on the opaque
dummy node used for the when of a missing node and on the root node.
Such a node has no value, so enum-value() returns NaN, bit-is-set()
false and deref() an empty node-set, as derived-from() already does.

Fixes CESNET#2604

@michalvasko michalvasko left a comment

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.

Looks good, thanks.

@michalvasko
michalvasko merged commit 8612c22 into CESNET:devel Nov 3, 2026
12 of 13 checks passed
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