Skip to content

Commit 2a34b5b

Browse files
committed
schema compile BUGFIX recompile union if needed
Fixes #2581
1 parent 23a8dcd commit 2a34b5b

2 files changed

Lines changed: 238 additions & 96 deletions

File tree

‎src/schema_compile_node.c‎

Lines changed: 142 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,115 @@ lys_new_type(const struct ly_ctx *ctx, LY_DATA_TYPE basetype, const char *tpdf_n
15871587
return rc;
15881588
}
15891589

1590+
/**
1591+
* @brief Check that a compiled type can be reused and shared.
1592+
*
1593+
* @param[in] type_p Parsed type.
1594+
* @param[in] type_c Compiled type.
1595+
* @param[in] pattern_format Global pattern format.
1596+
* @return 1 if @p type_c can be shared;
1597+
* @return 0 otherwise.
1598+
*/
1599+
static ly_bool
1600+
lys_compile_type_share_compiled(const struct lysp_type *type_p, const struct lysc_type *type_c, ly_bool pattern_format)
1601+
{
1602+
LYA_COUNT_T u;
1603+
struct lysc_type_union *type_un;
1604+
struct lysc_type_str *type_str = NULL;
1605+
1606+
if (!type_c) {
1607+
/* no compiled type to share */
1608+
return 0;
1609+
}
1610+
1611+
if (type_p && (type_p->flags || type_p->exts)) {
1612+
/* special type flags or extensions to be compiled */
1613+
return 0;
1614+
}
1615+
1616+
/* learn whether the type has a leafref, in which case it cannot be shared because it may resolve to a different
1617+
* real type for every instantiation */
1618+
if (type_c->basetype == LY_TYPE_LEAFREF) {
1619+
/* leafref type */
1620+
return 0;
1621+
} else if (type_c->basetype == LY_TYPE_UNION) {
1622+
/* union with a leafref */
1623+
type_un = (struct lysc_type_union *)type_c;
1624+
LYA_FOR(type_un->types, u) {
1625+
if (type_un->types[u]->basetype == LY_TYPE_LEAFREF) {
1626+
return 0;
1627+
}
1628+
}
1629+
}
1630+
1631+
/* check for patterns and their format */
1632+
if (type_c->basetype == LY_TYPE_STRING) {
1633+
type_str = (struct lysc_type_str *)type_c;
1634+
1635+
if (type_str->patterns && (type_str->patterns[0]->format != pattern_format)) {
1636+
return 0;
1637+
}
1638+
} else if (type_c->basetype == LY_TYPE_UNION) {
1639+
type_un = (struct lysc_type_union *)type_c;
1640+
LYA_FOR(type_un->types, u) {
1641+
if (type_un->types[u]->basetype == LY_TYPE_STRING) {
1642+
type_str = (struct lysc_type_str *)type_un->types[u];
1643+
1644+
if (type_str->patterns && (type_str->patterns[0]->format != pattern_format)) {
1645+
return 0;
1646+
}
1647+
}
1648+
}
1649+
}
1650+
1651+
return 1;
1652+
}
1653+
1654+
/**
1655+
* @brief Find a specific parsed type in the typedef chain.
1656+
*
1657+
* @param[in] tpdf_chain Set with the typedef chain.
1658+
* @param[in] tpdf_chain_last Index of @p tpdf_chain not to cross in descending order.
1659+
* @param[in] with_enum Set if looking for the first type with enums.
1660+
* @param[in] with_bits Set if looking for the first type with bits.
1661+
* @param[in] compiled Set if looking for the parsed type of this compiled type.
1662+
* @return Found parsed type.
1663+
*/
1664+
static const struct lysp_type *
1665+
lys_compile_type_find_parsed(const struct ly_set *tpdf_chain, uint32_t tpdf_chain_last, ly_bool with_enum, ly_bool with_bits,
1666+
const struct lysc_type *compiled)
1667+
{
1668+
const struct lysp_type *parsed = NULL;
1669+
const struct lys_type_item *tpdf_item;
1670+
uint32_t i;
1671+
1672+
assert(tpdf_chain->count > tpdf_chain_last);
1673+
assert((with_enum && !with_bits && !compiled) || (!with_enum && with_bits && !compiled) || (!with_enum && !with_bits && compiled));
1674+
1675+
i = tpdf_chain->count;
1676+
do {
1677+
--i;
1678+
tpdf_item = tpdf_chain->objs[i];
1679+
1680+
if (with_enum && tpdf_item->tpdf->type.enums) {
1681+
/* enums */
1682+
parsed = &tpdf_item->tpdf->type;
1683+
} else if (with_bits && tpdf_item->tpdf->type.bits) {
1684+
/* bits */
1685+
parsed = &tpdf_item->tpdf->type;
1686+
} else if (compiled) {
1687+
/* original type, must be the first */
1688+
parsed = &tpdf_item->tpdf->type;
1689+
assert(!parsed->compiled || (parsed->compiled == compiled));
1690+
assert(!compiled->name || (compiled->name == tpdf_item->tpdf->name));
1691+
assert(!strcmp(lys_datatype2str(compiled->basetype), parsed->name));
1692+
}
1693+
} while (!parsed && (i > tpdf_chain_last));
1694+
1695+
assert(parsed);
1696+
return parsed;
1697+
}
1698+
15901699
/**
15911700
* @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
15921701
*
@@ -1624,6 +1733,7 @@ lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_
16241733
const struct lysp_type *base_type_p;
16251734
struct lysc_prefix *prefixes;
16261735
uint32_t i;
1736+
ly_bool pattern_format, share_base;
16271737

16281738
/* alloc and init */
16291739
rc = lys_new_type(ctx->ctx, basetype, tpdfname, type);
@@ -1655,20 +1765,7 @@ lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_
16551765
(struct lysc_type_bitenum_item **)&bits->bits), cleanup);
16561766
} else if (base) {
16571767
/* recompile bits from the first superior type with bits */
1658-
assert(tpdf_chain->count > tpdf_chain_last);
1659-
base_type_p = NULL;
1660-
i = tpdf_chain->count;
1661-
do {
1662-
--i;
1663-
tpdf_item = tpdf_chain->objs[i];
1664-
1665-
if (tpdf_item->tpdf->type.bits) {
1666-
base_type_p = &tpdf_item->tpdf->type;
1667-
break;
1668-
}
1669-
} while (i > tpdf_chain_last);
1670-
assert(base_type_p);
1671-
1768+
base_type_p = lys_compile_type_find_parsed(tpdf_chain, tpdf_chain_last, 0, 1, NULL);
16721769
LY_CHECK_GOTO(rc = lys_compile_type_enums(ctx, base_type_p->bits, basetype, NULL,
16731770
(struct lysc_type_bitenum_item **)&bits->bits), cleanup);
16741771
} else {
@@ -1754,20 +1851,7 @@ lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_
17541851
base ? ((struct lysc_type_enum *)base)->enums : NULL, &enumeration->enums), cleanup);
17551852
} else if (base) {
17561853
/* recompile enums from the first superior type with enums */
1757-
assert(tpdf_chain->count > tpdf_chain_last);
1758-
base_type_p = NULL;
1759-
i = tpdf_chain->count;
1760-
do {
1761-
--i;
1762-
tpdf_item = tpdf_chain->objs[i];
1763-
1764-
if (tpdf_item->tpdf->type.enums) {
1765-
base_type_p = &tpdf_item->tpdf->type;
1766-
break;
1767-
}
1768-
} while (i > tpdf_chain_last);
1769-
assert(base_type_p);
1770-
1854+
base_type_p = lys_compile_type_find_parsed(tpdf_chain, tpdf_chain_last, 1, 0, NULL);
17711855
LY_CHECK_GOTO(rc = lys_compile_type_enums(ctx, base_type_p->enums, basetype, NULL, &enumeration->enums), cleanup);
17721856
} else {
17731857
/* type derived from enumerations built-in type must contain at least one enum */
@@ -1876,6 +1960,7 @@ lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_
18761960
assert(!prefixes[0].prefix);
18771961
prefixes[0].mod = ctx->cur_mod;
18781962
} else if (base) {
1963+
/* make a copy */
18791964
LY_CHECK_GOTO(rc = lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)base)->path, 0, 0, &lref->path), cleanup);
18801965
LY_CHECK_GOTO(rc = lyplg_type_prefix_data_dup(ctx->ctx, LY_VALUE_SCHEMA_RESOLVED,
18811966
((struct lysc_type_leafref *)base)->prefixes, (void **)&lref->prefixes), cleanup);
@@ -1928,15 +2013,38 @@ lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_
19282013
goto cleanup;
19292014
}
19302015
} else if (base) {
1931-
/* copy all the types */
2016+
/* copy all the types if possible */
19322017
const struct lysc_type_union *un_base = (struct lysc_type_union *)base;
19332018
LYA_COUNT_T u;
19342019

1935-
LYA_PREALLOC(un->types, LYA_COUNT(un_base->types), LOGMEM(ctx->ctx); rc = LY_EMEM; goto cleanup);
2020+
pattern_format = lys_compile_type_patterns_has_oc_posix_ext(ctx->pmod);
2021+
share_base = 1;
19362022
LYA_FOR(un_base->types, u) {
1937-
un->types[u] = un_base->types[u];
1938-
LY_ATOMIC_INC_BARRIER(un->types[u]->refcount);
1939-
LYA_INCREMENT(un->types);
2023+
if (un_base->types[u]->exts || !lys_compile_type_share_compiled(NULL, un_base->types[u], pattern_format)) {
2024+
/* cannot be shared */
2025+
share_base = 0;
2026+
break;
2027+
}
2028+
}
2029+
2030+
if (share_base) {
2031+
LYA_PREALLOC(un->types, LYA_COUNT(un_base->types), LOGMEM(ctx->ctx); rc = LY_EMEM; goto cleanup);
2032+
LYA_FOR(un_base->types, u) {
2033+
un->types[u] = un_base->types[u];
2034+
LY_ATOMIC_INC_BARRIER(un->types[u]->refcount);
2035+
LYA_INCREMENT(un->types);
2036+
}
2037+
} else {
2038+
/* free the prepared type */
2039+
lydict_remove(ctx->ctx, (*type)->name);
2040+
free(*type);
2041+
*type = NULL;
2042+
2043+
/* recompile the union */
2044+
base_type_p = lys_compile_type_find_parsed(tpdf_chain, tpdf_chain_last, 0, 0, base);
2045+
rc = lys_compile_type(ctx, context_pnode, context_flags, context_name, base_type_p, type, NULL, NULL);
2046+
LY_CHECK_GOTO(rc, cleanup);
2047+
assert(*type);
19402048
}
19412049
} else {
19422050
/* type derived from union built-in type must contain at least one type */
@@ -1978,64 +2086,6 @@ lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_
19782086
return rc;
19792087
}
19802088

1981-
/**
1982-
* @brief Check that a compiled type can be reused and shared.
1983-
*
1984-
* @param[in] type_p Parsed type.
1985-
* @param[in] type_c Compiled type.
1986-
* @param[in] pattern_format Global pattern format.
1987-
* @return 1 if @p type_c can be shared;
1988-
* @return 0 otherwise.
1989-
*/
1990-
static ly_bool
1991-
lys_compile_type_share_compiled(const struct lysp_type *type_p, const struct lysc_type *type_c, ly_bool pattern_format)
1992-
{
1993-
LYA_COUNT_T u;
1994-
struct lysc_type_union *type_un;
1995-
struct lysc_type_str *type_str = NULL;
1996-
1997-
if (!type_c || type_p->flags || type_p->exts) {
1998-
/* no compiled type to share, special type flags, or extensions */
1999-
return 0;
2000-
}
2001-
2002-
/* learn whether the type has a leafref, in which case it cannot be shared because it may resolve to a different
2003-
* real type for every instantiation */
2004-
if (type_c->basetype == LY_TYPE_LEAFREF) {
2005-
/* leafref type */
2006-
return 0;
2007-
} else if (type_c->basetype == LY_TYPE_UNION) {
2008-
/* union with a leafref */
2009-
type_un = (struct lysc_type_union *)type_c;
2010-
LYA_FOR(type_un->types, u) {
2011-
if (type_un->types[u]->basetype == LY_TYPE_LEAFREF) {
2012-
return 0;
2013-
}
2014-
}
2015-
}
2016-
2017-
/* check for patterns and their format */
2018-
if (type_c->basetype == LY_TYPE_STRING) {
2019-
type_str = (struct lysc_type_str *)type_c;
2020-
} else if (type_c->basetype == LY_TYPE_UNION) {
2021-
type_un = (struct lysc_type_union *)type_c;
2022-
LYA_FOR(type_un->types, u) {
2023-
if (type_un->types[u]->basetype == LY_TYPE_STRING) {
2024-
type_str = (struct lysc_type_str *)type_un->types[u];
2025-
break;
2026-
}
2027-
}
2028-
}
2029-
if (!type_str || !type_str->patterns) {
2030-
return 1;
2031-
}
2032-
2033-
if (pattern_format != type_str->patterns[0]->format) {
2034-
return 0;
2035-
}
2036-
return 1;
2037-
}
2038-
20392089
LY_ERR
20402090
lys_compile_type_find_tpdf(struct lysc_ctx *ctx, const struct lysp_node *context_pnode, uint16_t context_flags,
20412091
const char *context_name, const struct lysp_type *type_p, const char **units, struct lysp_qname **dflt,
@@ -2193,14 +2243,10 @@ lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t
21932243
ret = ly_set_add(&ctx->tpdf_chain, tctx, 1, NULL);
21942244
LY_CHECK_GOTO(ret, cleanup);
21952245

2196-
if (lys_compile_type_share_compiled(&tctx->tpdf->type, tctx->tpdf->type.compiled, pattern_format)) {
2246+
if (tctx->tpdf->type.compiled) {
21972247
/* already compiled, reuse */
21982248
base = tctx->tpdf->type.compiled;
21992249
continue;
2200-
} else if (tctx->tpdf->type.compiled) {
2201-
/* cannot reuse, replace the compiled type with our new compiled type */
2202-
LY_ATOMIC_DEC_BARRIER(tctx->tpdf->type.compiled->refcount);
2203-
((struct lysp_tpdf *)tctx->tpdf)->type.compiled = NULL;
22042250
}
22052251

22062252
/* try to find loaded user type plugins */

0 commit comments

Comments
 (0)