Skip to content

Commit f4fa90d

Browse files
committed
schema compile FEATURE disabled bits/enums unres
Do not remove the values right away to allow other checks (XPath) to finish first. Fixes CESNET/netopeer2#1048
1 parent aa95652 commit f4fa90d

File tree

8 files changed

+203
-18
lines changed

8 files changed

+203
-18
lines changed

src/schema_compile.c

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,75 @@ lys_compile_unres_must(struct lysc_ctx *ctx, const struct lysc_node *node, const
989989
return ret;
990990
}
991991

992+
/**
993+
* @brief Remove all disabled bits/enums from a sized array.
994+
*
995+
* @param[in] ctx Context with the dictionary.
996+
* @param[in] items Sized array of bits/enums.
997+
*/
998+
static void
999+
lys_compile_unres_disabled_bitenum_remove(struct ly_ctx *ctx, struct lysc_type_bitenum_item *items)
1000+
{
1001+
LY_ARRAY_COUNT_TYPE u = 0, last_u;
1002+
1003+
while (u < LY_ARRAY_COUNT(items)) {
1004+
if (items[u].flags & LYS_DISABLED) {
1005+
/* free the disabled item */
1006+
lysc_enum_item_free(ctx, &items[u]);
1007+
1008+
/* replace it with the following items */
1009+
last_u = LY_ARRAY_COUNT(items) - 1;
1010+
if (u < last_u) {
1011+
memmove(items + u, items + u + 1, (last_u - u) * sizeof *items);
1012+
}
1013+
1014+
/* one item less */
1015+
LY_ARRAY_DECREMENT(items);
1016+
continue;
1017+
}
1018+
1019+
++u;
1020+
}
1021+
}
1022+
1023+
/**
1024+
* @brief Find and remove all disabled bits/enums in a leaf/leaf-list type.
1025+
*
1026+
* @param[in] ctx Compile context.
1027+
* @param[in] leaf Leaf/leaf-list to check.
1028+
* @return LY_ERR value
1029+
*/
1030+
static LY_ERR
1031+
lys_compile_unres_disabled_bitenum(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf)
1032+
{
1033+
struct lysc_type **t;
1034+
LY_ARRAY_COUNT_TYPE u, count;
1035+
struct lysc_type_enum *ent;
1036+
1037+
if (leaf->type->basetype == LY_TYPE_UNION) {
1038+
t = ((struct lysc_type_union *)leaf->type)->types;
1039+
count = LY_ARRAY_COUNT(t);
1040+
} else {
1041+
t = &leaf->type;
1042+
count = 1;
1043+
}
1044+
for (u = 0; u < count; ++u) {
1045+
if ((t[u]->basetype == LY_TYPE_BITS) || (t[u]->basetype == LY_TYPE_ENUM)) {
1046+
/* remove all disabled items */
1047+
ent = (struct lysc_type_enum *)(t[u]);
1048+
lys_compile_unres_disabled_bitenum_remove(ctx->ctx, ent->enums);
1049+
1050+
if (!LY_ARRAY_COUNT(ent->enums)) {
1051+
LOGVAL(ctx->ctx, LYVE_SEMANTICS, "%s type of node \"%s\" without any (or all disabled) valid values.",
1052+
(ent->basetype == LY_TYPE_BITS) ? "Bits" : "Enumeration", leaf->name);
1053+
return LY_EVALID;
1054+
}
1055+
}
1056+
}
1057+
1058+
return LY_SUCCESS;
1059+
}
1060+
9921061
/**
9931062
* @brief Check leafref for its target existence on a complete compiled schema tree.
9941063
*
@@ -1375,6 +1444,20 @@ lys_compile_unres_depset(struct ly_ctx *ctx, struct lys_glob_unres *unres)
13751444
ly_set_rm_index(&ds_unres->musts, i, NULL);
13761445
}
13771446

1447+
/* remove disabled enums/bits */
1448+
for (i = 0; i < ds_unres->disabled_bitenums.count; ++i) {
1449+
node = ds_unres->disabled_bitenums.objs[i];
1450+
cctx.cur_mod = node->module;
1451+
cctx.pmod = node->module->parsed;
1452+
1453+
LOG_LOCSET(node, NULL, NULL, NULL);
1454+
ret = lys_compile_unres_disabled_bitenum(&cctx, (struct lysc_node_leaf *)node);
1455+
LOG_LOCBACK(1, 0, 0, 0);
1456+
LY_CHECK_RET(ret);
1457+
1458+
ly_set_rm_index(&ds_unres->disabled_bitenums, i, NULL);
1459+
}
1460+
13781461
/* finish incomplete default values compilation */
13791462
while (ds_unres->dflts.count) {
13801463
i = ds_unres->dflts.count - 1;
@@ -1462,8 +1545,9 @@ lys_compile_unres_depset_erase(const struct ly_ctx *ctx, struct lys_glob_unres *
14621545
lysc_unres_dflt_free(ctx, unres->ds_unres.dflts.objs[i]);
14631546
}
14641547
ly_set_erase(&unres->ds_unres.dflts, NULL);
1465-
ly_set_erase(&unres->ds_unres.disabled_leafrefs, free);
14661548
ly_set_erase(&unres->ds_unres.disabled, NULL);
1549+
ly_set_erase(&unres->ds_unres.disabled_leafrefs, free);
1550+
ly_set_erase(&unres->ds_unres.disabled_bitenums, NULL);
14671551
}
14681552

14691553
/**

src/schema_compile.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,11 @@ struct lys_depset_unres {
6565
struct ly_set musts; /**< set of musts to check */
6666
struct ly_set leafrefs; /**< to validate target of leafrefs */
6767
struct ly_set dflts; /**< set of incomplete default values */
68-
struct ly_set disabled; /**< set of compiled nodes whose if-feature(s) was not satisfied (stored ::lysc_node *) */
68+
struct ly_set disabled; /**< set of compiled nodes whose if-feature(s) was not satisfied
69+
(stored ::lysc_node *) */
6970
struct ly_set disabled_leafrefs; /**< subset of the lys_depset_unres.disabled to validate target of disabled leafrefs */
71+
struct ly_set disabled_bitenums; /**< set of enumation/bits leaves/leaf-lists with bits/enums to disable
72+
(stored ::lysc_node_leaf *) */
7073
};
7174

7275
/**

src/schema_compile_node.c

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,26 @@ lysc_unres_llist_dflts_add(struct lysc_ctx *ctx, struct lysc_node_leaflist *llis
243243
return LY_SUCCESS;
244244
}
245245

246+
/**
247+
* @brief Add a bits/enumeration type to unres.
248+
*
249+
* @param[in] ctx Compile context.
250+
* @param[in] leaf Leaf of type bits/enumeration whose disabled items to free.
251+
* @return LY_ERR value.
252+
*/
253+
static LY_ERR
254+
lysc_unres_bitenum_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf)
255+
{
256+
if (ctx->compile_opts & (LYS_COMPILE_DISABLED | LYS_COMPILE_GROUPING)) {
257+
/* skip groupings and redundant for disabled nodes */
258+
return LY_SUCCESS;
259+
}
260+
261+
LY_CHECK_RET(ly_set_add(&ctx->unres->disabled_bitenums, leaf, 1, NULL));
262+
263+
return LY_SUCCESS;
264+
}
265+
246266
/**
247267
* @brief Duplicate the compiled pattern structure.
248268
*
@@ -1457,12 +1477,6 @@ lys_compile_type_enums(struct lysc_ctx *ctx, struct lysp_type_enum *enums_p, LY_
14571477
}
14581478
}
14591479

1460-
/* evaluate if-ffeatures */
1461-
LY_CHECK_RET(lys_eval_iffeatures(ctx->ctx, enums_p[u].iffeatures, &enabled));
1462-
if (!enabled) {
1463-
continue;
1464-
}
1465-
14661480
/* add new enum/bit */
14671481
LY_ARRAY_NEW_RET(ctx->ctx, *bitenums, e, LY_EMEM);
14681482
DUP_STRING_GOTO(ctx->ctx, enums_p[u].name, e->name, ret, done);
@@ -1476,6 +1490,13 @@ lys_compile_type_enums(struct lysc_ctx *ctx, struct lysp_type_enum *enums_p, LY_
14761490
}
14771491
COMPILE_EXTS_GOTO(ctx, enums_p[u].exts, e->exts, e, ret, done);
14781492

1493+
/* evaluate if-ffeatures */
1494+
LY_CHECK_RET(lys_eval_iffeatures(ctx->ctx, enums_p[u].iffeatures, &enabled));
1495+
if (!enabled) {
1496+
/* set only flag, later resolved and removed */
1497+
e->flags |= LYS_DISABLED;
1498+
}
1499+
14791500
if (basetype == LY_TYPE_BITS) {
14801501
/* keep bits ordered by position */
14811502
for (v = u; v && (*bitenums)[v - 1].position > e->position; --v) {}
@@ -2783,6 +2804,9 @@ lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, stru
27832804
struct lysc_node_leaf *leaf)
27842805
{
27852806
struct lysp_qname *dflt;
2807+
struct lysc_type **t;
2808+
LY_ARRAY_COUNT_TYPE u, count;
2809+
ly_bool in_unres = 0;
27862810

27872811
LY_CHECK_RET(lys_compile_type(ctx, context_node, leaf->flags, leaf->name, type_p, &leaf->type,
27882812
leaf->units ? NULL : &leaf->units, &dflt));
@@ -2795,10 +2819,24 @@ lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, stru
27952819
/* store leafref(s) to be resolved */
27962820
LY_CHECK_RET(lysc_unres_leafref_add(ctx, leaf, type_p->pmod));
27972821

2798-
if (leaf->type->basetype == LY_TYPE_EMPTY) {
2799-
if ((leaf->nodetype == LYS_LEAFLIST) && (ctx->pmod->version < LYS_VERSION_1_1)) {
2800-
LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
2801-
return LY_EVALID;
2822+
/* type-specific checks */
2823+
if (leaf->type->basetype == LY_TYPE_UNION) {
2824+
t = ((struct lysc_type_union *)leaf->type)->types;
2825+
count = LY_ARRAY_COUNT(t);
2826+
} else {
2827+
t = &leaf->type;
2828+
count = 1;
2829+
}
2830+
for (u = 0; u < count; ++u) {
2831+
if (t[u]->basetype == LY_TYPE_EMPTY) {
2832+
if ((leaf->nodetype == LYS_LEAFLIST) && (ctx->pmod->version < LYS_VERSION_1_1)) {
2833+
LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
2834+
return LY_EVALID;
2835+
}
2836+
} else if (!in_unres && ((t[u]->basetype == LY_TYPE_BITS) || (t[u]->basetype == LY_TYPE_ENUM))) {
2837+
/* store in unres for all disabled bits/enums to be removed */
2838+
LY_CHECK_RET(lysc_unres_bitenum_add(ctx, leaf));
2839+
in_unres = 1;
28022840
}
28032841
}
28042842

src/tree_schema.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -840,11 +840,11 @@ struct lysp_deviation {
840840
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
841841
* 2 LYS_CONFIG_R |x|x|x|x|x|x|x| | | | | | | |
842842
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
843-
* 3 LYS_STATUS_CURR |x|x|x|x|x|x|x|x|x|x|x|x| |x|
843+
* 3 LYS_STATUS_CURR |x|x|x|x|x|x|x|x|x|x|x|x|x|x|
844844
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
845-
* 4 LYS_STATUS_DEPRC |x|x|x|x|x|x|x|x|x|x|x|x| |x|
845+
* 4 LYS_STATUS_DEPRC |x|x|x|x|x|x|x|x|x|x|x|x|x|x|
846846
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
847-
* 5 LYS_STATUS_OBSLT |x|x|x|x|x|x|x|x|x|x|x|x| |x|
847+
* 5 LYS_STATUS_OBSLT |x|x|x|x|x|x|x|x|x|x|x|x|x|x|
848848
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
849849
* 6 LYS_MAND_TRUE |x|x|x|x|x|x| | | | | | | | |
850850
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -856,6 +856,7 @@ struct lysp_deviation {
856856
* LYS_UNIQUE | | |x| | | | | | | | | | | |
857857
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
858858
* 9 LYS_KEY | | |x| | | | | | | | | | | |
859+
* LYS_DISABLED | | | | | | | | | | | | |x| |
859860
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
860861
* 10 LYS_SET_DFLT | | |x|x| | |x| | | | | | | |
861862
* LYS_IS_ENUM | | | | | | | | | | | | |x| |
@@ -903,6 +904,7 @@ struct lysp_deviation {
903904
#define LYS_UNIQUE 0x80 /**< flag for leafs being part of a unique set, applicable only to ::lysc_node_leaf */
904905
#define LYS_KEY 0x0100 /**< flag for leafs being a key of a list, applicable only to ::lysc_node_leaf */
905906
#define LYS_KEYLESS 0x0200 /**< flag for list without any key, applicable only to ::lysc_node_list */
907+
#define LYS_DISABLED 0x0100 /**< internal flag for a disabled statement, used only for bits/enums */
906908
#define LYS_FENABLED 0x20 /**< feature enabled flag, applicable only to ::lysp_feature. */
907909
#define LYS_ORDBY_SYSTEM 0x80 /**< ordered-by system configuration lists, applicable only to
908910
::lysc_node_leaflist/::lysp_node_leaflist and ::lysc_node_list/::lysp_node_list */
@@ -1571,8 +1573,8 @@ struct lysc_type_bitenum_item {
15711573
int32_t value; /**< integer value associated with the enumeration */
15721574
uint32_t position; /**< non-negative integer value associated with the bit */
15731575
};
1574-
uint16_t flags; /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_ and LYS_SET_VALUE
1575-
values are allowed */
1576+
uint16_t flags; /**< [schema node flags](@ref snodeflags) - only LYS_STATUS_ and LYS_IS_ENUM values
1577+
are allowed */
15761578
};
15771579

15781580
struct lysc_type_enum {

src/tree_schema_free.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ lysc_pattern_free(struct ly_ctx *ctx, struct lysc_pattern **pattern)
648648
free(*pattern);
649649
}
650650

651-
static void
651+
void
652652
lysc_enum_item_free(struct ly_ctx *ctx, struct lysc_type_bitenum_item *item)
653653
{
654654
lydict_remove(ctx, item->name);

src/tree_schema_internal.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,15 +692,25 @@ LY_ERR lysp_stmt_parse(struct lysc_ctx *ctx, const struct lysp_stmt *stmt, void
692692
*/
693693
void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node);
694694

695+
/**
696+
* @brief Free a bit/enum item.
697+
*
698+
* @param[in] ctx libyang context.
699+
* @param[in] item Bit/enum item to free.
700+
*/
701+
void lysc_enum_item_free(struct ly_ctx *ctx, struct lysc_type_bitenum_item *item);
702+
695703
/**
696704
* @brief Free the compiled type structure.
705+
*
697706
* @param[in] ctx libyang context where the string data resides in a dictionary.
698707
* @param[in,out] type Compiled type structure to be freed. The structure has refcount, so it is freed only in case the value is decreased to 0.
699708
*/
700709
void lysc_type_free(struct ly_ctx *ctx, struct lysc_type *type);
701710

702711
/**
703712
* @brief Free the compiled if-feature structure.
713+
*
704714
* @param[in] ctx libyang context where the string data resides in a dictionary.
705715
* @param[in,out] iff Compiled if-feature structure to be cleaned.
706716
* Since the structure is typically part of the sized array, the structure itself is not freed.
@@ -709,6 +719,7 @@ void lysc_iffeature_free(struct ly_ctx *ctx, struct lysc_iffeature *iff);
709719

710720
/**
711721
* @brief Free the compiled identity structure.
722+
*
712723
* @param[in] ctx libyang context where the string data resides in a dictionary.
713724
* @param[in,out] ident Compiled identity structure to be cleaned.
714725
* Since the structure is typically part of the sized array, the structure itself is not freed.
@@ -717,6 +728,7 @@ void lysc_ident_free(struct ly_ctx *ctx, struct lysc_ident *ident);
717728

718729
/**
719730
* @brief Free the compiled must structure.
731+
*
720732
* @param[in] ctx libyang context where the string data resides in a dictionary.
721733
* @param[in,out] must Compiled must structure to be cleaned.
722734
* Since the structure is typically part of the sized array, the structure itself is not freed.
@@ -741,6 +753,7 @@ void lysc_node_action_free(struct ly_ctx *ctx, struct lysc_node_action *action);
741753

742754
/**
743755
* @brief Free the items inside the compiled Notification structure.
756+
*
744757
* @param[in] ctx libyang context where the string data resides in a dictionary.
745758
* @param[in,out] notif Compiled Notification structure to be cleaned.
746759
* Since the structure is typically part of the sized array, the structure itself is not freed.
@@ -749,13 +762,15 @@ void lysc_node_notif_free(struct ly_ctx *ctx, struct lysc_node_notif *notif);
749762

750763
/**
751764
* @brief Free the compiled extension definition and NULL the provided pointer.
765+
*
752766
* @param[in] ctx libyang context where the string data resides in a dictionary.
753767
* @param[in,out] ext Compiled extension definition to be freed.
754768
*/
755769
void lysc_extension_free(struct ly_ctx *ctx, struct lysc_ext **ext);
756770

757771
/**
758772
* @brief Free the compiled extension instance structure.
773+
*
759774
* @param[in] ctx libyang context where the string data resides in a dictionary.
760775
* @param[in,out] ext Compiled extension instance structure to be cleaned.
761776
* Since the structure is typically part of the sized array, the structure itself is not freed.
@@ -764,6 +779,7 @@ void lysc_ext_instance_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext);
764779

765780
/**
766781
* @brief Free the compiled node structure.
782+
*
767783
* @param[in] ctx libyang context where the string data resides in a dictionary.
768784
* @param[in] node Compiled node structure to be freed.
769785
* @param[in] unlink Whether to first unlink the node before freeing.
@@ -783,12 +799,14 @@ void lysc_node_container_free(struct ly_ctx *ctx, struct lysc_node_container *no
783799

784800
/**
785801
* @brief Free the compiled schema structure.
802+
*
786803
* @param[in,out] module Compiled schema module structure to free.
787804
*/
788805
void lysc_module_free(struct lysc_module *module);
789806

790807
/**
791808
* @brief Free the schema structure. It just frees, it does not remove the schema from its context.
809+
*
792810
* @param[in,out] module Schema module structure to free.
793811
*/
794812
void lys_module_free(struct lys_module *module);

tests/utests/schema/test_schema.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ void test_collision_feature(void **state);
5050
void test_accessible_tree(void **state);
5151
void test_includes(void **state);
5252
void test_key_order(void **state);
53+
void test_disabled_enum(void **state);
5354

5455
/* test_schema_stmts.c */
5556
void test_identity(void **state);
@@ -74,6 +75,7 @@ main(void)
7475
UTEST(test_accessible_tree),
7576
UTEST(test_includes),
7677
UTEST(test_key_order),
78+
UTEST(test_disabled_enum),
7779

7880
/** test_schema_stmts.c */
7981
UTEST(test_identity),

0 commit comments

Comments
 (0)