Skip to content

parser BUGFIX move extension instance parents on array reallocation - #2590

Open
mardgez13 wants to merge 2 commits into
CESNET:develfrom
mardgez13:fix-yin-ext-parent
Open

mardgez13 wants to merge 2 commits into
CESNET:develfrom
mardgez13:fix-yin-ext-parent

Conversation

@mardgez13

@mardgez13 mardgez13 commented Oct 17, 2026 •

Copy link
Copy Markdown

Every struct lysp_ext_instance keeps a parent pointer to the statement it belongs to. That statement is often an item of a sized array (a typedef, enum, must, revision, import, ...), a member of such an item (&enum->flags for status, &tpdf->dflt for default), or the base of a separate array with parent_stmt_index (iffeatures, bases). When LYA_ADD_ITEM() grows the array and realloc() moves it, every such parent points into the freed memory.

  • parser_yin.c never updated these parents after adding an item, so they went stale whenever the array moved, and were later read through them (e.g. by lysp_ext_instance_path()).
  • parser_yang.c updated statement array items with a loop after each add, but reset every parent to the item itself, losing the member offsets of substatement parents (status, default, ...); parents into separate arrays such as iffeatures were not updated at all.
  • lysp_inject_submodule() grows the main module's includes without updating them either.

The fix adds one helper, lysp_ext_parents_move() (and LYSP_ARRAY_EXT_PARENTS_MOVE() for a whole array), which moves every parent that pointed into the previous array memory to the same offset in the new memory and leaves all others untouched. It is used at every place an array with extension instance parents grows, in both parsers and in lysp_inject_submodule(), replacing the per-site loops in parser_yang.c. With one helper, a new array of statements gets correct parents by calling it rather than by repeating a hand-written loop.

The second commit fixes another reference into a growing array in the YIN parser. yin_parse_fracdigits(), yin_pasrse_reqinstance() and yin_parse_value_pos() stored their parent's extension instance array (type->exts, enm->exts) in ctx->ext_inst while the parent type, enum or bit could still add more extension instances to it. A later extension instance of the parent could move the array, and lysp_resolve_ext_instance_records() then read the freed memory. The parent statements already store their array once they are parsed, as in the YANG parser, so these three calls are removed; every remaining call stores the array of the statement that was just parsed.

Tests:

  • test_ext_parent_array_realloc in tests/utests/schema/test_schema.c parses the same module in YANG and YIN with three typedefs (with default), enums (with status), musts and if-features, each with extension instances, and checks every parent points to its own statement, member or array.
  • tests/utests/basic/test_plugins.c loads the extension plugin test module in YIN too and adds musts to it; the parse callback now checks that the instance is the one stored in its parent, for enums, union types, musts, typedefs and refines in both formats.
  • test_yin_parse_type_substmt_exts in tests/utests/schema/test_yin.c parses fraction-digits, require-instance, value and position with an extension instance, each followed by more extension instances of its parent, and checks all of them are kept in order.

The full test suite passes (ASan/UBSan build).

Extension instances store a pointer to their parent statement, which
may be an item of a sized array, a member of such an item (flags,
an embedded type or default) or an item of a separate string array.
Adding an item to such an array may move it, so the parents went stale
in the YIN parser, which never updated them. The YANG parser reset
the parents of statement array items to the item itself, losing
the member offsets, and left the parents into separate arrays stale.

Add one helper moving every parent pointing into the previous array
memory to the same offset in the new one and use it wherever an array
with extension instance parents grows.
fraction-digits, require-instance, value and position stored
their parent's extension instance array for resolving while the
parent could still add more extension instances to it. Those
arrays are stored once the parent statement is parsed, the same
as in the YANG parser.
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.

1 participant