Skip to content

Commit 73f0ab8

Browse files
authored
union UPDATE unions with leafrefs returning misleading error codes (#2360)
* validate: unions with leafrefs may return misleading error codes When a leafref is not found in a union, it should not return an error indicating the value for the leafref wouldn't match the restrictions for a target but instead just say the leafref target wasn't found. The only data that should indicate the error message for data type restrictions is data associated with the target itself, not leafrefs. Signed-off-by: Brad House <[email protected]> * fixes as per @michalvasko * do not use lyd_value() * reference RFC in doxygen * error checking for OOM --------- Signed-off-by: Brad House <[email protected]>
1 parent f0574ac commit 73f0ab8

File tree

2 files changed

+67
-9
lines changed

2 files changed

+67
-9
lines changed

src/plugins_types/union.c

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,50 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c
150150
}
151151
}
152152

153+
/**
154+
* @brief For leafref failures, ensure the appropriate error is propagated, not a type validation failure.
155+
*
156+
* RFC7950 Section 15.5 defines the appropriate error app tag of "require-instance".
157+
*
158+
* @param[in,out] err Error record to be updated
159+
* @param[in] type leafref type used to extract target path
160+
* @param[in] value value attempting to be stored
161+
* @param[in] value_len Length of value that was attempted to be stored.
162+
* @return LY_ERR value. Only possible errors are LY_SUCCESS and LY_EMEM.
163+
*/
164+
static LY_ERR
165+
union_update_lref_err(struct ly_err_item *err, const struct lysc_type *type, const void *value, size_t value_len)
166+
{
167+
const struct lysc_type_leafref *lref;
168+
char *valstr = NULL;
169+
int msg_len;
170+
171+
if ((err == NULL) || (type->basetype != LY_TYPE_LEAFREF)) {
172+
return LY_SUCCESS;
173+
}
174+
175+
lref = (const struct lysc_type_leafref *)type;
176+
free(err->apptag);
177+
err->apptag = strdup("instance-required");
178+
if (err->apptag == NULL) {
179+
return LY_EMEM;
180+
}
181+
182+
free(err->msg);
183+
err->msg = NULL;
184+
valstr = strndup((const char *)value, value_len);
185+
if (valstr == NULL) {
186+
return LY_EMEM;
187+
}
188+
189+
msg_len = asprintf(&err->msg, LY_ERRMSG_NOLREF_VAL, valstr, lyxp_get_expr(lref->path));
190+
free(valstr);
191+
if (msg_len == -1) {
192+
return LY_EMEM;
193+
}
194+
return LY_SUCCESS;
195+
}
196+
153197
/**
154198
* @brief Store (and validate) subvalue as a specific type.
155199
*
@@ -170,7 +214,7 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3
170214
uint32_t options, ly_bool validate, const struct lyd_node *ctx_node, const struct lyd_node *tree,
171215
struct lys_glob_unres *unres, struct ly_err_item **err)
172216
{
173-
LY_ERR rc = LY_SUCCESS;
217+
LY_ERR urc, rc = LY_SUCCESS;
174218
struct lysc_type *type = type_u->types[type_idx];
175219
const void *value = NULL;
176220
size_t value_len = 0;
@@ -190,7 +234,13 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3
190234
if ((rc != LY_SUCCESS) && (rc != LY_EINCOMPLETE)) {
191235
/* clear any leftover/freed garbage */
192236
memset(&subvalue->value, 0, sizeof subvalue->value);
193-
return rc;
237+
238+
/* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */
239+
urc = union_update_lref_err(*err, type_u->types[ti], value, value_len);
240+
if (urc != LY_SUCCESS) {
241+
rc = urc;
242+
}
243+
goto cleanup;
194244
}
195245

196246
assert(subvalue->value.realtype);
@@ -219,16 +269,19 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3
219269
if (options & LYPLG_TYPE_STORE_ONLY) {
220270
opts |= LYPLG_TYPE_STORE_ONLY;
221271
}
222-
if (dynamic) {
223-
opts |= LYPLG_TYPE_STORE_DYNAMIC;
224-
}
225272

226273
rc = type->plugin->store(ctx, type, value, value_len, opts, format, prefix_data, subvalue->hints,
227274
subvalue->ctx_node, &subvalue->value, unres, err);
228275
if ((rc != LY_SUCCESS) && (rc != LY_EINCOMPLETE)) {
229276
/* clear any leftover/freed garbage */
230277
memset(&subvalue->value, 0, sizeof subvalue->value);
231-
return rc;
278+
279+
/* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */
280+
urc = union_update_lref_err(*err, type, value, value_len);
281+
if (urc != LY_SUCCESS) {
282+
rc = urc;
283+
}
284+
goto cleanup;
232285
}
233286

234287
if (validate && (rc == LY_EINCOMPLETE)) {
@@ -240,6 +293,10 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3
240293
}
241294
}
242295

296+
cleanup:
297+
if (dynamic) {
298+
free((void *)value);
299+
}
243300
return rc;
244301
}
245302

tests/utests/types/union.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ test_data_xml(void **state)
105105
TEST_ERROR_XML2("",
106106
"defs", "", "un1", "123456789012345678901", LY_EVALID);
107107
CHECK_LOG_CTX("Invalid union value \"123456789012345678901\" - no matching subtype found:\n"
108-
" libyang 2 - leafref, version 1: Invalid type int8 value \"123456789012345678901\".\n"
109-
" libyang 2 - leafref, version 1: Invalid type int64 value \"123456789012345678901\".\n"
108+
" libyang 2 - leafref, version 1: Invalid leafref value \"123456789012345678901\" - no target instance \"/int8\" with the same value.\n"
109+
" libyang 2 - leafref, version 1: Invalid leafref value \"123456789012345678901\" - no target instance \"/int64\" with the same value.\n"
110110
" libyang 2 - identityref, version 1: Invalid identityref \"123456789012345678901\" value - identity not found in module \"defs\".\n"
111111
" libyang 2 - instance-identifier, version 1: Invalid instance-identifier \"123456789012345678901\" value - syntax error.\n"
112112
" libyang 2 - string, version 1: Unsatisfied length - string \"123456789012345678901\" length is not allowed.\n",
@@ -295,7 +295,8 @@ test_validation(void **state)
295295
assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT, NULL));
296296
CHECK_LOG_CTX("Invalid LYB union value - no matching subtype found:\n"
297297
" libyang 2 - leafref, version 1: Invalid leafref value \"one\" - no target instance \"../../a/name\" with the same value.\n"
298-
" libyang 2 - leafref, version 1: Invalid type uint32 value \"one\".\n", "/lref:test/community[name='test']/view", 0);
298+
" libyang 2 - leafref, version 1: Invalid leafref value \"one\" - no target instance \"../../b/name\" with the same value.\n",
299+
"/lref:test/community[name='test']/view", 0);
299300

300301
lyd_free_all(tree);
301302
}

0 commit comments

Comments
 (0)