Commit message: resolve BUGFIX handle yet unresolved if-features

Fixes #772
CVE: CVE-2019-20391
CWE: CWE-119
Vulnerability description: An invalid memory access flaw is present in libyang before v1.0-r3 in the function resolve_feature_value() when an if-feature statement is used inside a bit. Applications that use libyang to parse untrusted input yang files may crash.

Project: libyang

resolve_len_ran_interval(struct ly_ctx *ctx, const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
{
    /* 0 - unsigned, 1 - signed, 2 - floating point */
    int kind;
    int64_t local_smin = 0, local_smax = 0, local_fmin, local_fmax;
    uint64_t local_umin, local_umax = 0;
    uint8_t local_fdig = 0;
    const char *seg_ptr, *ptr;
    struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;

    switch (type->base) {
    case LY_TYPE_BINARY:
        kind = 0;
        local_umin = 0;
        local_umax = 18446744073709551615UL;

        if (!str_restr && type->info.binary.length) {
            str_restr = type->info.binary.length->expr;
        }
        break;
    case LY_TYPE_DEC64:
        kind = 2;
        local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
        local_fmax = __INT64_C(9223372036854775807);
        local_fdig = type->info.dec64.dig;

        if (!str_restr && type->info.dec64.range) {
            str_restr = type->info.dec64.range->expr;
        }
        break;
    case LY_TYPE_INT8:
        kind = 1;
        local_smin = __INT64_C(-128);
        local_smax = __INT64_C(127);

        if (!str_restr && type->info.num.range) {
            str_restr = type->info.num.range->expr;
        }
        break;
    case LY_TYPE_INT16:
        kind = 1;
        local_smin = __INT64_C(-32768);
        local_smax = __INT64_C(32767);

        if (!str_restr && type->info.num.range) {
            str_restr = type->info.num.range->expr;
        }
        break;
    case LY_TYPE_INT32:
        kind = 1;
        local_smin = __INT64_C(-2147483648);
        local_smax = __INT64_C(2147483647);

        if (!str_restr && type->info.num.range) {
            str_restr = type->info.num.range->expr;
        }
        break;
    case LY_TYPE_INT64:
        kind = 1;
        local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
        local_smax = __INT64_C(9223372036854775807);

        if (!str_restr && type->info.num.range) {
            str_restr = type->info.num.range->expr;
        }
        break;
    case LY_TYPE_UINT8:
        kind = 0;
        local_umin = __UINT64_C(0);
        local_umax = __UINT64_C(255);

        if (!str_restr && type->info.num.range) {
            str_restr = type->info.num.range->expr;
        }
        break;
    case LY_TYPE_UINT16:
        kind = 0;
        local_umin = __UINT64_C(0);
        local_umax = __UINT64_C(65535);

        if (!str_restr && type->info.num.range) {
            str_restr = type->info.num.range->expr;
        }
        break;
    case LY_TYPE_UINT32:
        kind = 0;
        local_umin = __UINT64_C(0);
        local_umax = __UINT64_C(4294967295);

        if (!str_restr && type->info.num.range) {
            str_restr = type->info.num.range->expr;
        }
        break;
    case LY_TYPE_UINT64:
        kind = 0;
        local_umin = __UINT64_C(0);
        local_umax = __UINT64_C(18446744073709551615);

        if (!str_restr && type->info.num.range) {
            str_restr = type->info.num.range->expr;
        }
        break;
    case LY_TYPE_STRING:
        kind = 0;
        local_umin = __UINT64_C(0);
        local_umax = __UINT64_C(18446744073709551615);

        if (!str_restr && type->info.str.length) {
            str_restr = type->info.str.length->expr;
        }
        break;
    default:
        return -1;
    }

    /* process superior types */
    if (type->der) {
        if (resolve_len_ran_interval(ctx, NULL, &type->der->type, &intv)) {
            return -1;
        }
        assert(!intv || (intv->kind == kind));
    }

    if (!str_restr) {
        /* we do not have any restriction, return superior ones */
        *ret = intv;
        return EXIT_SUCCESS;
    }

    /* adjust local min and max */
    if (intv) {
        tmp_intv = intv;

        if (kind == 0) {
            local_umin = tmp_intv->value.uval.min;
        } else if (kind == 1) {
            local_smin = tmp_intv->value.sval.min;
        } else if (kind == 2) {
            local_fmin = tmp_intv->value.fval.min;
        }

        while (tmp_intv->next) {
            tmp_intv = tmp_intv->next;
        }

        if (kind == 0) {
            local_umax = tmp_intv->value.uval.max;
        } else if (kind == 1) {
            local_smax = tmp_intv->value.sval.max;
        } else if (kind == 2) {
            local_fmax = tmp_intv->value.fval.max;
        }
    }

    /* finally parse our restriction */
    seg_ptr = str_restr;
    tmp_intv = NULL;
    while (1) {
        if (!tmp_local_intv) {
            assert(!local_intv);
            local_intv = malloc(sizeof *local_intv);
            tmp_local_intv = local_intv;
        } else {
            tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
            tmp_local_intv = tmp_local_intv->next;
        }
        LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM(ctx), error);

        tmp_local_intv->kind = kind;
        tmp_local_intv->type = type;
        tmp_local_intv->next = NULL;

        /* min */
        ptr = seg_ptr;
        while (isspace(ptr[0])) {
            ++ptr;
        }
        if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
            if (kind == 0) {
                tmp_local_intv->value.uval.min = strtoull(ptr, (char **)&ptr, 10);
            } else if (kind == 1) {
                tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
            } else if (kind == 2) {
                if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
                    LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
                    goto error;
                }
            }
        } else if (!strncmp(ptr, "min", 3)) {
            if (kind == 0) {
                tmp_local_intv->value.uval.min = local_umin;
            } else if (kind == 1) {
                tmp_local_intv->value.sval.min = local_smin;
            } else if (kind == 2) {
                tmp_local_intv->value.fval.min = local_fmin;
            }

            ptr += 3;
        } else if (!strncmp(ptr, "max", 3)) {
            if (kind == 0) {
                tmp_local_intv->value.uval.min = local_umax;
            } else if (kind == 1) {
                tmp_local_intv->value.sval.min = local_smax;
            } else if (kind == 2) {
                tmp_local_intv->value.fval.min = local_fmax;
            }

            ptr += 3;
        } else {
            goto error;
        }

        while (isspace(ptr[0])) {
            ptr++;
        }

        /* no interval or interval */
        if ((ptr[0] == '|') || !ptr[0]) {
            if (kind == 0) {
                tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
            } else if (kind == 1) {
                tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
            } else if (kind == 2) {
                tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
            }
        } else if (!strncmp(ptr, "..", 2)) {
            /* skip ".." */
            ptr += 2;
            while (isspace(ptr[0])) {
                ++ptr;
            }

            /* max */
            if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
                if (kind == 0) {
                    tmp_local_intv->value.uval.max = strtoull(ptr, (char **)&ptr, 10);
                } else if (kind == 1) {
                    tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
                } else if (kind == 2) {
                    if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
                        LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
                        goto error;
                    }
                }
            } else if (!strncmp(ptr, "max", 3)) {
                if (kind == 0) {
                    tmp_local_intv->value.uval.max = local_umax;
                } else if (kind == 1) {
                    tmp_local_intv->value.sval.max = local_smax;
                } else if (kind == 2) {
                    tmp_local_intv->value.fval.max = local_fmax;
                }
            } else {
                goto error;
            }
        } else {
            goto error;
        }

        /* check min and max in correct order */
        if (kind == 0) {
            /* current segment */
            if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
                goto error;
            }
            if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
                goto error;
            }
            /* segments sholud be ascending order */
            if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
                goto error;
            }
        } else if (kind == 1) {
            if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
                goto error;
            }
            if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
                goto error;
            }
            if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
                goto error;
            }
        } else if (kind == 2) {
            if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
                goto error;
            }
            if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
                goto error;
            }
            if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
                /* fraction-digits value is always the same (it cannot be changed in derived types) */
                goto error;
            }
        }

        /* next segment (next OR) */
        seg_ptr = strchr(seg_ptr, '|');
        if (!seg_ptr) {
            break;
        }
        seg_ptr++;
        tmp_intv = tmp_local_intv;
    }

    /* check local restrictions against superior ones */
    if (intv) {
        tmp_intv = intv;
        tmp_local_intv = local_intv;

        while (tmp_local_intv && tmp_intv) {
            /* reuse local variables */
            if (kind == 0) {
                local_umin = tmp_local_intv->value.uval.min;
                local_umax = tmp_local_intv->value.uval.max;

                /* it must be in this interval */
                if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
                    /* this interval is covered, next one */
                    if (local_umax <= tmp_intv->value.uval.max) {
                        tmp_local_intv = tmp_local_intv->next;
                        continue;
                    /* ascending order of restrictions -> fail */
                    } else {
                        goto error;
                    }
                }
            } else if (kind == 1) {
                local_smin = tmp_local_intv->value.sval.min;
                local_smax = tmp_local_intv->value.sval.max;

                if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
                    if (local_smax <= tmp_intv->value.sval.max) {
                        tmp_local_intv = tmp_local_intv->next;
                        continue;
                    } else {
                        goto error;
                    }
                }
            } else if (kind == 2) {
                local_fmin = tmp_local_intv->value.fval.min;
                local_fmax = tmp_local_intv->value.fval.max;

                 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
                        && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
                    if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
                        tmp_local_intv = tmp_local_intv->next;
                        continue;
                    } else {
                        goto error;
                    }
                }
            }

            tmp_intv = tmp_intv->next;
        }

        /* some interval left uncovered -> fail */
        if (tmp_local_intv) {
            goto error;
        }
    }

    /* append the local intervals to all the intervals of the superior types, return it all */
    if (intv) {
        for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
        tmp_intv->next = local_intv;
    } else {
        intv = local_intv;
    }
    *ret = intv;

    return EXIT_SUCCESS;

error:
    while (intv) {
        tmp_intv = intv->next;
        free(intv);
        intv = tmp_intv;
    }
    while (local_intv) {
        tmp_local_intv = local_intv->next;
        free(local_intv);
        local_intv = tmp_local_intv;
    }

    return -1;
}

Project: libyang

resolve_partial_json_data_list_predicate(struct parsed_pred pp, struct lyd_node *node, int position)
{
    uint16_t i;
    char *val_str;
    struct lyd_node_leaf_list *key;
    struct lys_node_list *slist;
    struct ly_ctx *ctx;

    assert(node);
    assert(node->schema->nodetype == LYS_LIST);
    assert(pp.len);

    ctx = node->schema->module->ctx;
    slist = (struct lys_node_list *)node->schema;

    /* is the predicate a number? */
    if (isdigit(pp.pred[0].name[0])) {
        if (position == atoi(pp.pred[0].name)) {
            /* match */
            return 0;
        } else {
            /* not a match */
            return 1;
        }
    }

    key = (struct lyd_node_leaf_list *)node->child;
    if (!key) {
        /* it is not a position, so we need a key for it to be a match */
        return 1;
    }

    /* go through all the keys */
    for (i = 0; i < slist->keys_size; ++i) {
        if (strncmp(key->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || key->schema->name[pp.pred[i].nam_len]) {
            LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
            return -1;
        }

        if (pp.pred[i].mod_name) {
            /* specific module, check that the found key is from that module */
            if (strncmp(lyd_node_module((struct lyd_node *)key)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
                    || lyd_node_module((struct lyd_node *)key)->name[pp.pred[i].mod_name_len]) {
                LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
                return -1;
            }

            /* but if the module is the same as the parent, it should have been omitted */
            if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
                LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
                return -1;
            }
        } else {
            /* no module, so it must be the same as the list (parent) */
            if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
                LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
                return -1;
            }
        }

        /* get canonical value */
        val_str = lyd_make_canonical(key->schema, pp.pred[i].value, pp.pred[i].val_len);
        if (!val_str) {
            return -1;
        }

        /* value does not match */
        if (strcmp(key->value_str, val_str)) {
            free(val_str);
            return 1;
        }
        free(val_str);

        key = (struct lyd_node_leaf_list *)key->next;
    }

    return 0;
}

Project: libyang

resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
{
    enum LY_VLOG_ELEM vlog_type;
    void *vlog_node;
    unsigned int i, j;
    struct lys_ext *e;
    char *ext_name, *ext_prefix, *tmp;
    struct lyxml_elem *next_yin, *yin;
    const struct lys_module *mod;
    struct lys_ext_instance *tmp_ext;
    struct ly_ctx *ctx = NULL;
    LYEXT_TYPE etype;

    switch (info->parent_type) {
    case LYEXT_PAR_NODE:
        vlog_node = info->parent;
        vlog_type = LY_VLOG_LYS;
        break;
    case LYEXT_PAR_MODULE:
    case LYEXT_PAR_IMPORT:
    case LYEXT_PAR_INCLUDE:
        vlog_node = NULL;
        vlog_type = LY_VLOG_LYS;
        break;
    default:
        vlog_node = NULL;
        vlog_type = LY_VLOG_NONE;
        break;
    }

    if (info->datatype == LYS_IN_YIN) {
        /* YIN */

        /* get the module where the extension is supposed to be defined */
        mod = lyp_get_import_module_ns(info->mod, info->data.yin->ns->value);
        if (!mod) {
            LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
            return EXIT_FAILURE;
        }
        ctx = mod->ctx;

        /* find the extension definition */
        e = NULL;
        for (i = 0; i < mod->extensions_size; i++) {
            if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
                e = &mod->extensions[i];
                break;
            }
        }
        /* try submodules */
        for (j = 0; !e && j < mod->inc_size; j++) {
            for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
                if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
                    e = &mod->inc[j].submodule->extensions[i];
                    break;
                }
            }
        }
        if (!e) {
            LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
            return EXIT_FAILURE;
        }

        /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */

        if (e->plugin && e->plugin->check_position) {
            /* common part - we have plugin with position checking function, use it first */
            if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
                /* extension is not allowed here */
                LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
                return -1;
            }
        }

        /* extension type-specific part - allocation */
        if (e->plugin) {
            etype = e->plugin->type;
        } else {
            /* default type */
            etype = LYEXT_FLAG;
        }
        switch (etype) {
        case LYEXT_FLAG:
            (*ext) = calloc(1, sizeof(struct lys_ext_instance));
            break;
        case LYEXT_COMPLEX:
            (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
            break;
        case LYEXT_ERR:
            /* we never should be here */
            LOGINT(ctx);
            return -1;
        }
        LY_CHECK_ERR_RETURN(!*ext, LOGMEM(ctx), -1);

        /* common part for all extension types */
        (*ext)->def = e;
        (*ext)->parent = info->parent;
        (*ext)->parent_type = info->parent_type;
        (*ext)->insubstmt = info->substmt;
        (*ext)->insubstmt_index = info->substmt_index;
        (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
        (*ext)->flags |= e->plugin ? e->plugin->flags : 0;

        if (e->argument) {
            if (!(e->flags & LYS_YINELEM)) {
                (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
                if (!(*ext)->arg_value) {
                    LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
                    return -1;
                }

                (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
            } else {
                LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
                    if (ly_strequal(yin->name, e->argument, 1)) {
                        (*ext)->arg_value = lydict_insert(mod->ctx, yin->content, 0);
                        lyxml_free(mod->ctx, yin);
                        break;
                    }
                }
            }
        }

        if ((*ext)->flags & LYEXT_OPT_VALID &&
            (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
            ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
        }

        (*ext)->nodetype = LYS_EXT;
        (*ext)->module = info->mod;

        /* extension type-specific part - parsing content */
        switch (etype) {
        case LYEXT_FLAG:
            LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
                if (!yin->ns) {
                    /* garbage */
                    lyxml_free(mod->ctx, yin);
                    continue;
                } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
                    /* standard YANG statements are not expected here */
                    LOGVAL(ctx, LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
                    return -1;
                } else if (yin->ns == info->data.yin->ns &&
                        (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
                    /* we have the extension's argument */
                    if ((*ext)->arg_value) {
                        LOGVAL(ctx, LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
                        return -1;
                    }
                    (*ext)->arg_value = yin->content;
                    yin->content = NULL;
                    lyxml_free(mod->ctx, yin);
                } else {
                    /* extension instance */
                    if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
                                                  LYEXT_SUBSTMT_SELF, 0, unres)) {
                        return -1;
                    }

                    continue;
                }
            }
            break;
        case LYEXT_COMPLEX:
            ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
            if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
                /* TODO memory cleanup */
                return -1;
            }
            break;
        default:
            break;
        }

        /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */

    } else {
        /* YANG */

        ext_prefix = (char *)(*ext)->def;
        tmp = strchr(ext_prefix, ':');
        if (!tmp) {
            LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
            goto error;
        }
        ext_name = tmp + 1;

        /* get the module where the extension is supposed to be defined */
        mod = lyp_get_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0, 0);
        if (!mod) {
            LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
            return EXIT_FAILURE;
        }
        ctx = mod->ctx;

        /* find the extension definition */
        e = NULL;
        for (i = 0; i < mod->extensions_size; i++) {
            if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
                e = &mod->extensions[i];
                break;
            }
        }
        /* try submodules */
        for (j = 0; !e && j < mod->inc_size; j++) {
            for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
                if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
                    e = &mod->inc[j].submodule->extensions[i];
                    break;
                }
            }
        }
        if (!e) {
            LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
            return EXIT_FAILURE;
        }

        (*ext)->flags &= ~LYEXT_OPT_YANG;
        (*ext)->def = NULL;

        /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */

        if (e->plugin && e->plugin->check_position) {
            /* common part - we have plugin with position checking function, use it first */
            if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
                /* extension is not allowed here */
                LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
                goto error;
            }
        }

        if (e->argument && !(*ext)->arg_value) {
            LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
            goto error;
        }

        /* extension common part */
        (*ext)->def = e;
        (*ext)->parent = info->parent;
        (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
        (*ext)->flags |= e->plugin ? e->plugin->flags : 0;

        if ((*ext)->flags & LYEXT_OPT_VALID &&
            (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
            ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
        }

        (*ext)->module = info->mod;
        (*ext)->nodetype = LYS_EXT;

        /* extension type-specific part */
        if (e->plugin) {
            etype = e->plugin->type;
        } else {
            /* default type */
            etype = LYEXT_FLAG;
        }
        switch (etype) {
        case LYEXT_FLAG:
            /* nothing change */
            break;
        case LYEXT_COMPLEX:
            tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
            LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM(ctx), error);
            memset((char *)tmp_ext + offsetof(struct lys_ext_instance_complex, content), 0,
                   ((struct lyext_plugin_complex*)e->plugin)->instance_size - offsetof(struct lys_ext_instance_complex, content));
            (*ext) = tmp_ext;
            ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
            if (info->data.yang) {
                *tmp = ':';
                if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
                                                (struct lys_ext_instance_complex*)(*ext))) {
                    goto error;
                }
                if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
                                                info->data.yang->ext_modules, info->mod->implemented)) {
                    goto error;
                }
            }
            if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
                goto error;
            }
            break;
        case LYEXT_ERR:
            /* we never should be here */
            LOGINT(ctx);
            goto error;
        }

        if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
            goto error;
        }
        free(ext_prefix);
    }

    return EXIT_SUCCESS;
error:
    free(ext_prefix);
    return -1;
}

Project: libyang

resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
              struct lys_type **resolved_type)
{
    struct ly_ctx *ctx = leaf->schema->module->ctx;
    struct lys_type *t;
    struct lyd_node *ret;
    enum int_log_opts prev_ilo;
    int found, success = 0, ext_dep, req_inst;
    const char *json_val = NULL;

    assert(type->base == LY_TYPE_UNION);

    if ((leaf->value_type == LY_TYPE_UNION) || ((leaf->value_type == LY_TYPE_INST) && (leaf->value_flags & LY_VALUE_UNRES))) {
        /* either NULL or instid previously converted to JSON */
        json_val = lydict_insert(ctx, leaf->value.string, 0);
    }

    if (store) {
        lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, &((struct lys_node_leaf *)leaf->schema)->type,
                       leaf->value_str, NULL, NULL, NULL);
        memset(&leaf->value, 0, sizeof leaf->value);
    }

    /* turn logging off, we are going to try to validate the value with all the types in order */
    ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, 0);

    t = NULL;
    found = 0;
    while ((t = lyp_get_next_union_type(type, t, &found))) {
        found = 0;

        switch (t->base) {
        case LY_TYPE_LEAFREF:
            if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
                req_inst = -1;
            } else {
                req_inst = t->info.lref.req;
            }

            if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
                if (store) {
                    if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
                        /* valid resolved */
                        leaf->value.leafref = ret;
                        leaf->value_type = LY_TYPE_LEAFREF;
                    } else {
                        /* valid unresolved */
                        ly_ilo_restore(NULL, prev_ilo, NULL, 0);
                        if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0, 0)) {
                            return -1;
                        }
                        ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
                    }
                }

                success = 1;
            }
            break;
        case LY_TYPE_INST:
            ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
            if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
                req_inst = -1;
            } else {
                req_inst = t->info.inst.req;
            }

            if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
                if (store) {
                    if (ret && !ext_dep) {
                        /* valid resolved */
                        leaf->value.instance = ret;
                        leaf->value_type = LY_TYPE_INST;

                        if (json_val) {
                            lydict_remove(leaf->schema->module->ctx, leaf->value_str);
                            leaf->value_str = json_val;
                            json_val = NULL;
                        }
                    } else {
                        /* valid unresolved */
                        if (json_val) {
                            /* put the JSON val back */
                            leaf->value.string = json_val;
                            json_val = NULL;
                        } else {
                            leaf->value.instance = NULL;
                        }
                        leaf->value_type = LY_TYPE_INST;
                        leaf->value_flags |= LY_VALUE_UNRES;
                    }
                }

                success = 1;
            }
            break;
        default:
            if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, store, 0, 0)) {
                success = 1;
            }
            break;
        }

        if (success) {
            break;
        }

        /* erase possible present and invalid value data */
        if (store) {
            lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, t, leaf->value_str, NULL, NULL, NULL);
            memset(&leaf->value, 0, sizeof leaf->value);
        }
    }

    /* turn logging back on */
    ly_ilo_restore(NULL, prev_ilo, NULL, 0);

    if (json_val) {
        if (!success) {
            /* put the value back for now */
            assert(leaf->value_type == LY_TYPE_UNION);
            leaf->value.string = json_val;
        } else {
            /* value was ultimately useless, but we could not have known */
            lydict_remove(leaf->schema->module->ctx, json_val);
        }
    }

    if (success) {
        if (resolved_type) {
            *resolved_type = t;
        }
    } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
        /* not found and it is required */
        LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;

}

Project: libyang

resolve_schema_leafref(struct lys_type *type, struct lys_node *parent, struct unres_schema *unres)
{
    const struct lys_node *node, *op_node = NULL, *tmp_parent;
    struct ly_set *node_set;
    struct lys_node_augment *last_aug;
    const struct lys_module *tmp_mod, *cur_module;
    const char *id, *prefix, *name;
    int pref_len, nam_len, parent_times, has_predicate;
    int i, first_iter;
    struct ly_ctx *ctx = parent->module->ctx;

    first_iter = 1;
    parent_times = 0;
    id = type->info.lref.path;
    node_set = ly_set_new();
    if (!node_set) {
        LOGMEM(ctx);
        return -1;
    }

    /* find operation schema we are in */
    for (op_node = lys_parent(parent);
        op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
        op_node = lys_parent(op_node));

    cur_module = lys_node_module(parent);
    do {
        if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
            LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
            ly_set_free(node_set);
            return -1;
        }
        id += i;

        /* get the current module */
        tmp_mod = prefix ? lyp_get_module(cur_module, NULL, 0, prefix, pref_len, 0) : cur_module;
        if (!tmp_mod) {
            LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
            ly_set_free(node_set);
            return EXIT_FAILURE;
        }
        last_aug = NULL;

        if (first_iter) {
            if (parent_times == -1) {
                /* use module data */
                node = NULL;

            } else if (parent_times > 0) {
                /* we are looking for the right parent */
                for (i = 0, node = parent; i < parent_times; i++) {
                    if (node->parent && (node->parent->nodetype == LYS_AUGMENT)
                            && !((struct lys_node_augment *)node->parent)->target) {
                        /* we are in an unresolved augment, cannot evaluate */
                        LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, node->parent,
                            "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", type->info.lref.path);
                        ly_set_free(node_set);
                        return EXIT_FAILURE;
                    }

                    /* path is supposed to be evaluated in data tree, so we have to skip
                     * all schema nodes that cannot be instantiated in data tree */
                    for (node = lys_parent(node);
                        node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
                        node = lys_parent(node));

                    if (!node) {
                        if (i == parent_times - 1) {
                            /* top-level */
                            break;
                        }

                        /* higher than top-level */
                        LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
                        ly_set_free(node_set);
                        return EXIT_FAILURE;
                    }
                }
            } else {
                LOGINT(ctx);
                ly_set_free(node_set);
                return -1;
            }
        }

        /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
         * - useless to search for that in augments) */
        if (!tmp_mod->implemented && node) {
    get_next_augment:
            last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
        }

        tmp_parent = (last_aug ? (struct lys_node *)last_aug : node);
        node = NULL;
        while ((node = lys_getnext(node, tmp_parent, tmp_mod, LYS_GETNEXT_NOSTATECHECK))) {
            if (lys_node_module(node) != lys_main_module(tmp_mod)) {
                continue;
            }
            if (strncmp(node->name, name, nam_len) || node->name[nam_len]) {
                continue;
            }
            /* match */
            break;
        }
        if (!node) {
            if (last_aug) {
                /* restore the correct augment target */
                node = last_aug->target;
                goto get_next_augment;
            }
            LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
            ly_set_free(node_set);
            return EXIT_FAILURE;
        }

        if (first_iter) {
            /* set external dependency flag, we can decide based on the first found node */
            if (resolve_schema_leafref_valid_dep_flag(op_node, cur_module, node, (parent_times == -1 ? 1 : 0))) {
                parent->flags |= LYS_LEAFREF_DEP;
            }
            first_iter = 0;
        }

        if (has_predicate) {
            /* we have predicate, so the current result must be list */
            if (node->nodetype != LYS_LIST) {
                LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
                ly_set_free(node_set);
                return -1;
            }

            i = resolve_schema_leafref_predicate(id, node, parent, node_set);
            if (!i) {
                ly_set_free(node_set);
                return EXIT_FAILURE;
            } else if (i < 0) {
                ly_set_free(node_set);
                return -1;
            }
            id += i;
            has_predicate = 0;
        }
    } while (id[0]);

    /* the target must be leaf or leaf-list (in YANG 1.1 only) */
    if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
        LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
        LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", type->info.lref.path);
        ly_set_free(node_set);
        return -1;
    }

    /* check status */
    if (lyp_check_status(parent->flags, parent->module, parent->name,
                    node->flags, node->module, node->name, node)) {
        ly_set_free(node_set);
        return -1;
    }

    /* assign */
    type->info.lref.target = (struct lys_node_leaf *)node;

    /* add the target node into a set so its parent chain modules can be implemented */
    ly_set_add(node_set, (void *)node, 0);

    /* as the last thing traverse this leafref and make targets on the path implemented */
    if (lys_node_module(parent)->implemented) {
        /* make all the modules in the path implemented */
        for (i = 0; (unsigned)i < node_set->number; ++i) {
            for (node = node_set->set.s[i]; node; node = lys_parent(node)) {
                if (!lys_node_module(node)->implemented) {
                    lys_node_module(node)->implemented = 1;
                    if (unres_schema_add_node(lys_node_module(node), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
                        ly_set_free(node_set);
                        return -1;
                    }
                }
            }
        }

        /* store the backlink from leafref target */
        if (lys_leaf_add_leafref_target(type->info.lref.target, (struct lys_node *)type->parent)) {
            ly_set_free(node_set);
            return -1;
        }
    }
    ly_set_free(node_set);

    /* check if leafref and its target are under common if-features */
    return check_leafref_features(type);
}

Project: libyang

resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
                          int infeature, struct unres_schema *unres)
{
    const char *c = value;
    int r, rc = EXIT_FAILURE;
    int i, j, last_not, checkversion = 0;
    unsigned int f_size = 0, expr_size = 0, f_exp = 1;
    uint8_t op;
    struct iff_stack stack = {0, 0, NULL};
    struct unres_iffeat_data *iff_data;
    struct ly_ctx *ctx = node->module->ctx;

    assert(c);

    if (isspace(c[0])) {
        LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
        return EXIT_FAILURE;
    }

    /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
    for (i = j = last_not = 0; c[i]; i++) {
        if (c[i] == '(') {
            checkversion = 1;
            j++;
            continue;
        } else if (c[i] == ')') {
            j--;
            continue;
        } else if (isspace(c[i])) {
            continue;
        }

        if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
            if (c[i + r] == '\0') {
                LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
                return EXIT_FAILURE;
            } else if (!isspace(c[i + r])) {
                /* feature name starting with the not/and/or */
                last_not = 0;
                f_size++;
            } else if (c[i] == 'n') { /* not operation */
                if (last_not) {
                    /* double not */
                    expr_size = expr_size - 2;
                    last_not = 0;
                } else {
                    last_not = 1;
                }
            } else { /* and, or */
                f_exp++;
                /* not a not operation */
                last_not = 0;
            }
            i += r;
        } else {
            f_size++;
            last_not = 0;
        }
        expr_size++;

        while (!isspace(c[i])) {
            if (c[i] == '(') {
                LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
                return EXIT_FAILURE;
            } else if (!c[i] || c[i] == ')') {
                i--;
                break;
            }
            i++;
        }
    }
    if (j || f_exp != f_size) {
        /* not matching count of ( and ) */
        LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
        return EXIT_FAILURE;
    }

    if (checkversion || expr_size > 1) {
        /* check that we have 1.1 module */
        if (node->module->version != LYS_VERSION_1_1) {
            LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
            LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
            return EXIT_FAILURE;
        }
    }

    /* allocate the memory */
    iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
    iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
    stack.stack = malloc(expr_size * sizeof *stack.stack);
    LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM(ctx), error);
    stack.size = expr_size;
    f_size--; expr_size--; /* used as indexes from now */

    for (i--; i >= 0; i--) {
        if (c[i] == ')') {
            /* push it on stack */
            iff_stack_push(&stack, LYS_IFF_RP);
            continue;
        } else if (c[i] == '(') {
            /* pop from the stack into result all operators until ) */
            while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
                iff_setop(iffeat_expr->expr, op, expr_size--);
            }
            continue;
        } else if (isspace(c[i])) {
            continue;
        }

        /* end operator or operand -> find beginning and get what is it */
        j = i + 1;
        while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
            i--;
        }
        i++; /* get back by one step */

        if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
            if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
                /* double not */
                iff_stack_pop(&stack);
            } else {
                /* not has the highest priority, so do not pop from the stack
                 * as in case of AND and OR */
                iff_stack_push(&stack, LYS_IFF_NOT);
            }
        } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
            /* as for OR - pop from the stack all operators with the same or higher
             * priority and store them to the result, then push the AND to the stack */
            while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
                op = iff_stack_pop(&stack);
                iff_setop(iffeat_expr->expr, op, expr_size--);
            }
            iff_stack_push(&stack, LYS_IFF_AND);
        } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
            while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
                op = iff_stack_pop(&stack);
                iff_setop(iffeat_expr->expr, op, expr_size--);
            }
            iff_stack_push(&stack, LYS_IFF_OR);
        } else {
            /* feature name, length is j - i */

            /* add it to the result */
            iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);

            /* now get the link to the feature definition. Since it can be
             * forward referenced, we have to keep the feature name in auxiliary
             * structure passed into unres */
            iff_data = malloc(sizeof *iff_data);
            LY_CHECK_ERR_GOTO(!iff_data, LOGMEM(ctx), error);
            iff_data->node = node;
            iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
            iff_data->infeature = infeature;
            r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
                                      (struct lys_node *)iff_data);
            f_size--;

            if (r == -1) {
                lydict_remove(node->module->ctx, iff_data->fname);
                free(iff_data);
                goto error;
            }
        }
    }
    while (stack.index) {
        op = iff_stack_pop(&stack);
        iff_setop(iffeat_expr->expr, op, expr_size--);
    }

    if (++expr_size || ++f_size) {
        /* not all expected operators and operands found */
        LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
        rc = EXIT_FAILURE;
    } else {
        rc = EXIT_SUCCESS;
    }

error:
    /* cleanup */
    iff_stack_clean(&stack);

    return rc;
}

Project: libyang

check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
{
    struct lys_tpdf *base_tpdf = NULL;
    struct lyd_node_leaf_list node;
    const char *dflt = NULL;
    char *s;
    int ret = EXIT_SUCCESS, r;
    struct ly_ctx *ctx = module->ctx;

    assert(value);
    memset(&node, 0, sizeof node);

    if (type->base <= LY_TYPE_DER) {
        /* the type was not resolved yet, nothing to do for now */
        ret = EXIT_FAILURE;
        goto cleanup;
    } else if (!tpdf && !module->implemented) {
        /* do not check defaults in not implemented module's data */
        goto cleanup;
    } else if (tpdf && !module->implemented && type->base == LY_TYPE_IDENT) {
        /* identityrefs are checked when instantiated in data instead of typedef,
         * but in typedef the value has to be modified to include the prefix */
        if (*value) {
            if (strchr(*value, ':')) {
                dflt = transform_schema2json(module, *value);
            } else {
                /* default prefix of the module where the typedef is defined */
                if (asprintf(&s, "%s:%s", lys_main_module(module)->name, *value) == -1) {
                    LOGMEM(ctx);
                    ret = -1;
                    goto cleanup;
                }
                dflt = lydict_insert_zc(ctx, s);
            }
            lydict_remove(ctx, *value);
            *value = dflt;
            dflt = NULL;
        }
        goto cleanup;
    } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
        /* leafref in typedef cannot be checked */
        goto cleanup;
    }

    dflt = lydict_insert(ctx, *value, 0);
    if (!dflt) {
        /* we do not have a new default value, so is there any to check even, in some base type? */
        for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
            if (base_tpdf->dflt) {
                dflt = lydict_insert(ctx, base_tpdf->dflt, 0);
                break;
            }
        }

        if (!dflt) {
            /* no default value, nothing to check, all is well */
            goto cleanup;
        }

        /* so there is a default value in a base type, but can the default value be no longer valid (did we define some new restrictions)? */
        switch (type->base) {
        case LY_TYPE_IDENT:
            if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
                goto cleanup;
            } else {
                /* check the default value from typedef, but use also the typedef's module
                 * due to possible searching in imported modules which is expected in
                 * typedef's module instead of module where the typedef is used */
                module = base_tpdf->module;
            }
            break;
        case LY_TYPE_INST:
        case LY_TYPE_LEAFREF:
        case LY_TYPE_BOOL:
        case LY_TYPE_EMPTY:
            /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
            goto cleanup;
        case LY_TYPE_BITS:
            /* the default value must match the restricted list of values, if the type was restricted */
            if (type->info.bits.count) {
                break;
            }
            goto cleanup;
        case LY_TYPE_ENUM:
            /* the default value must match the restricted list of values, if the type was restricted */
            if (type->info.enums.count) {
                break;
            }
            goto cleanup;
        case LY_TYPE_DEC64:
            if (type->info.dec64.range) {
                break;
            }
            goto cleanup;
        case LY_TYPE_BINARY:
            if (type->info.binary.length) {
                break;
            }
            goto cleanup;
        case LY_TYPE_INT8:
        case LY_TYPE_INT16:
        case LY_TYPE_INT32:
        case LY_TYPE_INT64:
        case LY_TYPE_UINT8:
        case LY_TYPE_UINT16:
        case LY_TYPE_UINT32:
        case LY_TYPE_UINT64:
            if (type->info.num.range) {
                break;
            }
            goto cleanup;
        case LY_TYPE_STRING:
            if (type->info.str.length || type->info.str.patterns) {
                break;
            }
            goto cleanup;
        case LY_TYPE_UNION:
            /* way too much trouble learning whether we need to check the default again, so just do it */
            break;
        default:
            LOGINT(ctx);
            ret = -1;
            goto cleanup;
        }
    } else if (type->base == LY_TYPE_EMPTY) {
        LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
        LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
        ret = -1;
        goto cleanup;
    }

    /* dummy leaf */
    memset(&node, 0, sizeof node);
    node.value_str = lydict_insert(ctx, dflt, 0);
    node.value_type = type->base;

    if (tpdf) {
        node.schema = calloc(1, sizeof (struct lys_node_leaf));
        if (!node.schema) {
            LOGMEM(ctx);
            ret = -1;
            goto cleanup;
        }
        r = asprintf((char **)&node.schema->name, "typedef-%s-default", ((struct lys_tpdf *)type->parent)->name);
        if (r == -1) {
            LOGMEM(ctx);
            ret = -1;
            goto cleanup;
        }
        node.schema->module = module;
        memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
    } else {
        node.schema = (struct lys_node *)type->parent;
    }

    if (type->base == LY_TYPE_LEAFREF) {
        if (!type->info.lref.target) {
            ret = EXIT_FAILURE;
            LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Default value \"%s\" cannot be checked in an unresolved leafref.",
                   dflt);
            goto cleanup;
        }
        ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
        if (!ret) {
            /* adopt possibly changed default value to its canonical form */
            if (*value) {
                lydict_remove(ctx, *value);
                *value = dflt;
                dflt = NULL;
            }
        }
    } else {
        if (!lyp_parse_value(type, &node.value_str, NULL, &node, NULL, module, 1, 1, 0)) {
            /* possible forward reference */
            ret = EXIT_FAILURE;
            if (base_tpdf) {
                /* default value is defined in some base typedef */
                if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
                        (type->base == LY_TYPE_ENUM && type->der->type.der)) {
                    /* we have refined bits/enums */
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
                           "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
                           dflt, type->parent->name, base_tpdf->name);
                }
            }
        } else {
            /* success - adopt canonical form from the node into the default value */
            if (!ly_strequal(dflt, node.value_str, 1)) {
                /* this can happen only if we have non-inherited default value,
                 * inherited default values are already in canonical form */
                assert(ly_strequal(dflt, *value, 1));

                lydict_remove(ctx, *value);
                *value = node.value_str;
                node.value_str = NULL;
            }
        }
    }

cleanup:
    lyd_free_value(node.value, node.value_type, node.value_flags, type, node.value_str, NULL, NULL, NULL);
    lydict_remove(ctx, node.value_str);
    if (tpdf && node.schema) {
        free((char *)node.schema->name);
        free(node.schema);
    }
    lydict_remove(ctx, dflt);

    return ret;
}

Project: libyang

resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node, struct lys_node *parent,
                                 struct ly_set *node_set)
{
    const struct lys_module *trg_mod;
    const struct lys_node *src_node, *dst_node, *tmp_parent;
    struct lys_node_augment *last_aug;
    const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
    int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
    int has_predicate, dest_parent_times, i, rc;
    struct ly_ctx *ctx = context_node->module->ctx;

    do {
        if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
                                      &pke_len, &has_predicate)) < 1) {
            LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path[-i], path - i);
            return -parsed + i;
        }
        parsed += i;
        path += i;

        /* source (must be leaf) */
        if (sour_pref) {
            trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len, 0);
        } else {
            trg_mod = lys_node_module(parent);
        }
        rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, LYS_GETNEXT_NOSTATECHECK,
                              &src_node);
        if (rc) {
            LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path-parsed);
            return 0;
        }

        /* destination */
        dest_parent_times = 0;
        pke_parsed = 0;
        if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
                                     &dest_parent_times)) < 1) {
            LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path_key_expr[-i], path_key_expr-i);
            return -parsed;
        }
        pke_parsed += i;

        for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
            if (!dst_node) {
                /* we went too much into parents, there is no parent anymore */
                LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
                return 0;
            }

            if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
                    && !((struct lys_node_augment *)dst_node->parent)->target) {
                /* we are in an unresolved augment, cannot evaluate */
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
                       "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
                return 0;
            }

            /* path is supposed to be evaluated in data tree, so we have to skip
             * all schema nodes that cannot be instantiated in data tree */
            for (dst_node = lys_parent(dst_node);
                 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
                 dst_node = lys_parent(dst_node));
        }
        while (1) {
            last_aug = NULL;

            if (dest_pref) {
                trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len, 0);
            } else {
                trg_mod = lys_node_module(parent);
            }

            if (!trg_mod->implemented && dst_node) {
    get_next_augment:
                last_aug = lys_getnext_target_aug(last_aug, trg_mod, dst_node);
            }

            tmp_parent = (last_aug ? (struct lys_node *)last_aug : dst_node);
            rc = lys_getnext_data(trg_mod, tmp_parent, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF,
                                  LYS_GETNEXT_NOSTATECHECK, &dst_node);
            if (rc) {
                if (last_aug) {
                    /* restore the correct augment target */
                    dst_node = last_aug->target;
                    goto get_next_augment;
                }
                LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
                return 0;
            }

            if (pke_len == pke_parsed) {
                break;
            }

            if ((i = parse_path_key_expr(path_key_expr + pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
                                         &dest_parent_times)) < 1) {
                LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent,
                       (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed) - i);
                return -parsed;
            }
            pke_parsed += i;
        }

        /* check source - dest match */
        if (dst_node->nodetype != src_node->nodetype) {
            LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path - parsed);
            LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
                   strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
            return -parsed;
        }

        /* add both nodes into node set */
        ly_set_add(node_set, (void *)dst_node, 0);
        ly_set_add(node_set, (void *)src_node, 0);
    } while (has_predicate);

    return parsed;
}

Project: libyang

resolve_iffeature(struct lys_iffeature *expr)
{
    int index_e = 0, index_f = 0;

    if (expr->expr && expr->features[0]) {
        return resolve_iffeature_recursive(expr, &index_e, &index_f);
    }
    return 0;
}