libyang: CHANGE: review code and validity checks according to RFC 6020 sec 7.2 and 7.3
- submodule statement and its substatements
- typedef statements
diff --git a/src/parser/yin.c b/src/parser/yin.c
index c101fdd..0b4fd61 100644
--- a/src/parser/yin.c
+++ b/src/parser/yin.c
@@ -62,6 +62,20 @@
static struct ly_mnode *read_yin_uses(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
static struct ly_mnode *read_yin_grouping(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
+static int dup_typedef_check(const char* type, struct ly_tpdf *tpdf, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!strcmp(type, tpdf[i].name)) {
+ /* name collision */
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
static int dup_prefix_check(const char* prefix, struct ly_module *module)
{
int i;
@@ -82,6 +96,10 @@
struct ly_module *module, struct ly_mnode *parent)
{
int i;
+ int size;
+ struct ly_tpdf *tpdf;
+
+
assert(id);
@@ -103,7 +121,76 @@
}
switch(type) {
+ case LY_IDENT_TYPE:
+ assert(module);
+
+ /* check collision with the built-in types */
+ if (!strcmp(id, "binary") || !strcmp(id,"bits") ||
+ !strcmp(id, "boolean") || !strcmp(id, "decimal64") ||
+ !strcmp(id, "empty") || !strcmp(id, "enumeration") ||
+ !strcmp(id, "identityref") || !strcmp(id, "instance-identifier") ||
+ !strcmp(id, "int8") || !strcmp(id, "int16") ||
+ !strcmp(id, "int32") || !strcmp(id, "int64") ||
+ !strcmp(id, "leafref") || !strcmp(id, "string") ||
+ !strcmp(id, "uint8") || !strcmp(id, "uint16") ||
+ !strcmp(id, "uint32") || !strcmp(id, "uint64") ||
+ !strcmp(id, "union")) {
+ LOGVAL(VE_SPEC, line, "Typedef name duplicates built-in type.");
+ return EXIT_FAILURE;
+ }
+
+ /* check locally scoped typedefs (avoid name shadowing) */
+ for ( ; parent; parent = parent->parent) {
+ switch(parent->nodetype) {
+ case LY_NODE_CONTAINER:
+ size = ((struct ly_mnode_container *)parent)->tpdf_size;
+ tpdf = ((struct ly_mnode_container *)parent)->tpdf;
+ break;
+ case LY_NODE_LIST:
+ size = ((struct ly_mnode_list *)parent)->tpdf_size;
+ tpdf = ((struct ly_mnode_list *)parent)->tpdf;
+ break;
+ case LY_NODE_GROUPING:
+ size = ((struct ly_mnode_grp *)parent)->tpdf_size;
+ tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
+ break;
+ default:
+ continue;
+ }
+
+ if (dup_typedef_check(id, tpdf, size)) {
+ LOGVAL(VE_DUPID, line, "typedef", id);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* check top-level names */
+ if (dup_typedef_check(id, module->tpdf, module->tpdf_size)) {
+ LOGVAL(VE_DUPID, line, "typedef", id);
+ return EXIT_FAILURE;
+ }
+
+ /* check submodule's top-level names */
+ for (i = 0; i < module->inc_size; i++) {
+ if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
+ LOGVAL(VE_DUPID, line, "typedef", id);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* check top-level names in the main module */
+ if (module->type) {
+ if (dup_typedef_check(id, ((struct ly_submodule *)module)->belongsto->tpdf,
+ ((struct ly_submodule *)module)->belongsto->tpdf_size)) {
+ LOGVAL(VE_DUPID, line, "typedef", id);
+ return EXIT_FAILURE;
+ }
+ }
+
+ break;
case LY_IDENT_PREFIX:
+ assert(module);
+
if (module->type) {
/* go to the main module */
module = ((struct ly_submodule *)module)->belongsto;
@@ -131,6 +218,13 @@
return EXIT_SUCCESS;
}
+static int check_default(struct ly_tpdf *tpdf)
+{
+ /* TODO - RFC 6020, sec. 7.3.4 */
+ (void)tpdf;
+ return EXIT_SUCCESS;
+}
+
static int check_date(const char* date, unsigned int line)
{
int i;
@@ -607,49 +701,60 @@
struct lyxml_elem *node, *next;
int r = 0;
- value = lyxml_get_attr(yin, "name", NULL);
+ GETVAL(value, yin, "name");
+ if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
+ goto error;
+ }
tpdf->name = lydict_insert(module->ctx, value, strlen(value));
+ /* generic part - status, description, reference */
+ if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, 0)) {
+ goto error;
+ }
+
LY_TREE_FOR_SAFE(yin->child, next, node) {
if (!strcmp(node->name, "type")) {
r = fill_yin_type(module, parent, node, &tpdf->type);
-
- /* optional statements */
- } else if (!strcmp(node->name, "description")) {
- tpdf->dsc = read_yin_text(module->ctx, node);
- if (!tpdf->dsc) {
- r = 1;
+ } else if (!strcmp(node->name, "default")) {
+ if (tpdf->dflt) {
+ LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
+ goto error;
}
- } else if (!strcmp(node->name, "reference")) {
- tpdf->ref = read_yin_text(module->ctx, node);
- if (!tpdf->ref) {
- r = 1;
+ GETVAL(value, node, "value");
+ tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
+ } else if (!strcmp(node->name, "units")) {
+ if (tpdf->units) {
+ LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
+ goto error;
}
- } else if (!strcmp(node->name, "status")) {
- value = lyxml_get_attr(node, "value", NULL);
- if (!strcmp(value, "current")) {
- tpdf->flags |= LY_NODE_STATUS_CURR;
- } else if (!strcmp(value, "deprecated")) {
- tpdf->flags |= LY_NODE_STATUS_DEPRC;
- } else if (!strcmp(value, "obsolete")) {
- tpdf->flags |= LY_NODE_STATUS_OBSLT;
- } else {
- LOGVAL(VE_INARG, LOGLINE(node), value, "status");
- r = 1;
- }
+ GETVAL(value, node, "name");
+ tpdf->units = lydict_insert(module->ctx, value, strlen(value));
+ } else {
+ LOGVAL(VE_INSTMT, LOGLINE(node), value);
+ r = 1;
}
lyxml_free_elem(module->ctx, node);
if (r) {
- return EXIT_FAILURE;
+ goto error;
}
}
+ /* check mandatory value */
if (!tpdf->type.der) {
LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", "typedef");
- return EXIT_FAILURE;
+ goto error;
+ }
+
+ /* default value */
+ if (check_default(tpdf)) {
+ goto error;
}
return EXIT_SUCCESS;
+
+error:
+
+ return EXIT_FAILURE;
}
static int fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
@@ -771,23 +876,35 @@
mnode->name = lydict_insert(ctx, value, strlen(value));
if (!mnode->name || !mnode->name[0]) {
LOGVAL(VE_MISSARG, LOGLINE(xmlnode), "name", xmlnode->name);
- return EXIT_FAILURE;
+ goto error;
}
/* process local parameters */
LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
if (!strcmp(sub->name, "description")) {
+ if (mnode->dsc) {
+ LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
+ goto error;
+ }
mnode->dsc = read_yin_text(ctx, sub);
if (!mnode->dsc) {
r = 1;
}
} else if (!strcmp(sub->name, "reference")) {
+ if (mnode->ref) {
+ LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
+ goto error;
+ }
mnode->ref = read_yin_text(ctx, sub);
if (!mnode->ref) {
r = 1;
}
} else if (!strcmp(sub->name, "status")) {
- value = lyxml_get_attr(sub, "value", NULL);
+ if (mnode->flags & LY_NODE_STATUS_MASK) {
+ LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
+ goto error;
+ }
+ GETVAL(value, sub, "value");
if (!strcmp(value, "current")) {
mnode->flags |= LY_NODE_STATUS_CURR;
} else if (!strcmp(value, "deprecated")) {
@@ -799,7 +916,11 @@
r = 1;
}
} else if (ext && !strcmp(sub->name, "config")) {
- value = lyxml_get_attr(sub, "value", NULL);
+ if (mnode->flags & LY_NODE_CONFIG_MASK) {
+ LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
+ goto error;
+ }
+ GETVAL(value, sub, "value");
if (!strcmp(value, "false")) {
mnode->flags |= LY_NODE_CONFIG_R;
} else if (!strcmp(value, "false")) {
@@ -814,7 +935,7 @@
}
lyxml_free_elem(ctx, sub);
if (r) {
- EXIT_FAILURE;
+ goto error;
}
}
@@ -829,6 +950,10 @@
}
return EXIT_SUCCESS;
+
+error:
+
+ return EXIT_FAILURE;
}
static struct ly_mnode *read_yin_choice(struct ly_module *module,