Skip to content

Commit 1f00f0c

Browse files
Nathan Chandrasekarclaude
authored andcommitted
plugins types REFACTOR build strings with ly_append_str
The bits, identityref, instance-identifier-keys, xpath1.0 and union type plugins grew their strings by computing each realloc() size by hand and then writing into the buffer with sprintf() or strcpy(). Use ly_append_str() instead, which sizes the buffer from the formatted output itself, so no length computation has to be kept in sync with the format string. The IPv4/IPv6 zone suffix is now printed with snprintf() bounded by the allocated size. ly_append_str() now checks for vsnprintf() failure and size overflow and is declared with printf format checking. ly_strcat() checks for vasprintf() failure and no longer leaks on realloc() failure. Printed values and error messages are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 927fce9 commit 1f00f0c

10 files changed

Lines changed: 93 additions & 95 deletions

File tree

‎src/ly_common.c‎

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,25 +1803,29 @@ ly_strcat(char **dest, const char *format, ...)
18031803
{
18041804
va_list fp;
18051805
char *addition = NULL;
1806-
size_t len;
1806+
size_t dest_len;
1807+
int add_len;
18071808

18081809
va_start(fp, format);
1809-
len = vasprintf(&addition, format, fp);
1810-
len += (*dest ? strlen(*dest) : 0) + 1;
1810+
add_len = vasprintf(&addition, format, fp);
1811+
va_end(fp);
1812+
if (add_len == -1) {
1813+
return LY_EMEM;
1814+
}
18111815

18121816
if (*dest) {
1813-
*dest = ly_realloc(*dest, len);
1817+
dest_len = strlen(*dest);
1818+
*dest = ly_realloc(*dest, dest_len + add_len + 1);
18141819
if (!*dest) {
1815-
va_end(fp);
1820+
free(addition);
18161821
return LY_EMEM;
18171822
}
1818-
*dest = strcat(*dest, addition);
1823+
memcpy(*dest + dest_len, addition, add_len + 1);
18191824
free(addition);
18201825
} else {
18211826
*dest = addition;
18221827
}
18231828

1824-
va_end(fp);
18251829
return LY_SUCCESS;
18261830
}
18271831

@@ -1992,8 +1996,20 @@ ly_append_str(char **str, uint32_t *size, uint32_t *used, const char *format, ..
19921996

19931997
/* try to append the string */
19941998
p = vsnprintf(*str ? *str + *used : NULL, *size - *used, format, ap);
1999+
if (p < 0) {
2000+
va_end(ap);
2001+
LOGERR(NULL, LY_ESYS, "Failed to print a string (%s).", strerror(errno));
2002+
return LY_ESYS;
2003+
}
19952004

19962005
if ((unsigned)p >= *size - *used) {
2006+
/* the new size must fit into the size type */
2007+
if ((unsigned)p >= UINT32_MAX - *size) {
2008+
va_end(ap);
2009+
LOGMEM(NULL);
2010+
return LY_EMEM;
2011+
}
2012+
19972013
/* realloc */
19982014
*str = ly_realloc(*str, *size + p + 1);
19992015
LY_CHECK_ERR_RET(!*str, LOGMEM(NULL), LY_EMEM);

‎src/ly_common.h‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -830,14 +830,16 @@ LY_ERR ly_val_get_quot(const struct ly_ctx *ctx, const char *value, char *quot);
830830
/**
831831
* @brief Append a string to a dynamic string variable.
832832
*
833-
* @param[in,out] str String to use.
833+
* The string is reallocated as needed so the caller never computes the length of the appended text.
834+
*
835+
* @param[in,out] str String to use, may be NULL (with @p size and @p used 0) to create a new string.
834836
* @param[in,out] size String size.
835-
* @param[in,out] used String used size excluding terminating zero. If NULL, 0 is assumed.
837+
* @param[in,out] used String used size excluding terminating zero.
836838
* @param[in] format Message format.
837839
* @param[in] ... Message format arguments.
838840
* @return LY_ERR value.
839841
*/
840-
LY_ERR ly_append_str(char **str, uint32_t *size, uint32_t *used, const char *format, ...);
842+
LY_ERR ly_append_str(char **str, uint32_t *size, uint32_t *used, const char *format, ...) _FORMAT_PRINTF(4, 5);
841843

842844
/**
843845
* @brief mmap(2) wrapper to map input files into memory to unify parsing.

‎src/plugins_types/bits.c‎

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -261,30 +261,20 @@ static LY_ERR
261261
bits_items2canon(struct lysc_type_bitenum_item **items, char **canonical)
262262
{
263263
char *ret;
264-
uint32_t ret_len;
264+
uint32_t ret_size, ret_len;
265265
LYA_COUNT_T u;
266266

267267
*canonical = NULL;
268268

269269
/* init value */
270270
ret = strdup("");
271271
LY_CHECK_RET(!ret, LY_EMEM);
272+
ret_size = 1;
272273
ret_len = 0;
273274

274275
LYA_FOR(items, u) {
275-
if (!ret_len) {
276-
ret = ly_realloc(ret, strlen(items[u]->name) + 1);
277-
LY_CHECK_RET(!ret, LY_EMEM);
278-
strcpy(ret, items[u]->name);
279-
280-
ret_len = strlen(ret);
281-
} else {
282-
ret = ly_realloc(ret, ret_len + 1 + strlen(items[u]->name) + 1);
283-
LY_CHECK_RET(!ret, LY_EMEM);
284-
sprintf(ret + ret_len, " %s", items[u]->name);
285-
286-
ret_len += 1 + strlen(items[u]->name);
287-
}
276+
LY_CHECK_ERR_RET(ly_append_str(&ret, &ret_size, &ret_len, "%s%s", ret_len ? " " : "", items[u]->name),
277+
free(ret), LY_EMEM);
288278
}
289279

290280
*canonical = ret;

‎src/plugins_types/identityref.c‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ identityref_check_base(const struct lysc_ident *ident, struct lysc_type_identity
148148
uint32_t value_size, struct ly_err_item **err)
149149
{
150150
LY_ERR ret;
151-
uint32_t str_len;
151+
uint32_t str_size, str_len;
152152
char *str;
153153
LYA_COUNT_T u;
154154
struct lysc_ident *base;
@@ -164,12 +164,15 @@ identityref_check_base(const struct lysc_ident *ident, struct lysc_type_identity
164164
/* it does not, generate a nice error */
165165
if (u == LYA_COUNT(type->bases)) {
166166
str = NULL;
167-
str_len = 1;
167+
str_size = 0;
168+
str_len = 0;
168169
LYA_FOR(type->bases, u) {
169170
base = type->bases[u];
170-
str_len += (u ? 2 : 0) + 1 + strlen(base->module->name) + 1 + strlen(base->name) + 1;
171-
str = ly_realloc(str, str_len);
172-
sprintf(str + (u ? strlen(str) : 0), "%s\"%s:%s\"", u ? ", " : "", base->module->name, base->name);
171+
if (ly_append_str(&str, &str_size, &str_len, "%s\"%s:%s\"", u ? ", " : "", base->module->name,
172+
base->name)) {
173+
free(str);
174+
return ly_err_new_no_mem(err);
175+
}
173176
}
174177

175178
/* no match */

‎src/plugins_types/instanceid_keys.c‎

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,9 @@ instanceid_keys_print_value(const struct lyd_value_instance_identifier_keys *val
6060
char **str_value, struct ly_err_item **err)
6161
{
6262
LY_ERR ret = LY_SUCCESS;
63-
uint32_t cur_idx = 0, str_len = 0;
63+
uint32_t cur_idx = 0, str_size = 0, str_len = 0;
6464
enum lyxp_token cur_tok;
6565
char *str_tok;
66-
void *mem;
6766
const char *cur_exp_ptr;
6867
ly_bool is_nt;
6968
const struct lys_module *context_mod = NULL, *local_mod = NULL;
@@ -89,27 +88,16 @@ instanceid_keys_print_value(const struct lyd_value_instance_identifier_keys *val
8988
val->ctx, val->format, val->prefix_data, format, prefix_data, &str_tok, err), cleanup);
9089

9190
/* append the converted token */
92-
mem = realloc(*str_value, str_len + strlen(str_tok) + 1);
93-
if (!mem) {
94-
free(str_tok);
95-
ret = ly_err_new_no_mem(err);
96-
goto cleanup;
97-
}
98-
*str_value = mem;
99-
str_len += sprintf(*str_value + str_len, "%s", str_tok);
91+
ret = ly_append_str(str_value, &str_size, &str_len, "%s", str_tok);
10092
free(str_tok);
93+
LY_CHECK_ERR_GOTO(ret, ret = ly_err_new_no_mem(err), cleanup);
10194

10295
/* token processed */
10396
++cur_idx;
10497
} else {
10598
/* just copy the token */
106-
mem = realloc(*str_value, str_len + val->keys->tok_len[cur_idx] + 1);
107-
if (!mem) {
108-
ret = ly_err_new_no_mem(err);
109-
goto cleanup;
110-
}
111-
*str_value = mem;
112-
str_len += sprintf(*str_value + str_len, "%.*s", (int)val->keys->tok_len[cur_idx], cur_exp_ptr);
99+
ret = ly_append_str(str_value, &str_size, &str_len, "%.*s", (int)val->keys->tok_len[cur_idx], cur_exp_ptr);
100+
LY_CHECK_ERR_GOTO(ret, ret = ly_err_new_no_mem(err), cleanup);
113101

114102
/* token processed */
115103
++cur_idx;

‎src/plugins_types/ipv4_address.c‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ lyplg_type_print_ipv4_address(const struct ly_ctx *ctx, const struct lyd_value *
251251
void *UNUSED(prefix_data), ly_bool *dynamic, uint64_t *value_size_bits)
252252
{
253253
struct lyd_value_ipv4_address *val;
254-
uint32_t zone_len;
254+
uint32_t zone_len, ret_size, ret_len;
255255
char *ret;
256256

257257
LYD_VALUE_GET(value, val);
@@ -285,7 +285,8 @@ lyplg_type_print_ipv4_address(const struct ly_ctx *ctx, const struct lyd_value *
285285
if (!value->_canonical) {
286286
/* '%' + zone */
287287
zone_len = val->zone ? strlen(val->zone) + 1 : 0;
288-
ret = malloc(INET_ADDRSTRLEN + zone_len);
288+
ret_size = INET_ADDRSTRLEN + zone_len;
289+
ret = malloc(ret_size);
289290
LY_CHECK_RET(!ret, NULL);
290291

291292
/* get the address in string */
@@ -297,7 +298,8 @@ lyplg_type_print_ipv4_address(const struct ly_ctx *ctx, const struct lyd_value *
297298

298299
/* add zone */
299300
if (zone_len) {
300-
sprintf(ret + strlen(ret), "%%%s", val->zone);
301+
ret_len = strlen(ret);
302+
snprintf(ret + ret_len, ret_size - ret_len, "%%%s", val->zone);
301303
}
302304

303305
/* store it */

‎src/plugins_types/ipv6_address.c‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ lyplg_type_print_ipv6_address(const struct ly_ctx *ctx, const struct lyd_value *
253253
void *UNUSED(prefix_data), ly_bool *dynamic, uint64_t *value_size_bits)
254254
{
255255
struct lyd_value_ipv6_address *val;
256-
uint32_t zone_len;
256+
uint32_t zone_len, ret_size, ret_len;
257257
char *ret;
258258

259259
LYD_VALUE_GET(value, val);
@@ -287,7 +287,8 @@ lyplg_type_print_ipv6_address(const struct ly_ctx *ctx, const struct lyd_value *
287287
if (!value->_canonical) {
288288
/* '%' + zone */
289289
zone_len = val->zone ? strlen(val->zone) + 1 : 0;
290-
ret = malloc(INET6_ADDRSTRLEN + zone_len);
290+
ret_size = INET6_ADDRSTRLEN + zone_len;
291+
ret = malloc(ret_size);
291292
LY_CHECK_RET(!ret, NULL);
292293

293294
/* get the address in string */
@@ -299,7 +300,8 @@ lyplg_type_print_ipv6_address(const struct ly_ctx *ctx, const struct lyd_value *
299300

300301
/* add zone */
301302
if (zone_len) {
302-
sprintf(ret + strlen(ret), "%%%s", val->zone);
303+
ret_len = strlen(ret);
304+
snprintf(ret + ret_len, ret_size - ret_len, "%%%s", val->zone);
303305
}
304306

305307
/* store it */

‎src/plugins_types/union.c‎

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -433,12 +433,12 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct
433433
uint32_t options, const struct lyd_node *ctx_node, const struct lyd_node *tree, uint32_t *type_idx,
434434
struct lys_glob_unres *unres, struct ly_err_item **err)
435435
{
436-
LY_ERR rc = LY_SUCCESS;
436+
LY_ERR rc = LY_SUCCESS, r;
437437
LYA_COUNT_T u;
438438
struct ly_err_item **errs = NULL, *e;
439439
uint32_t *prev_lo, temp_lo = 0;
440440
char *msg = NULL, *err_app_tag = NULL;
441-
int msg_len = 0;
441+
uint32_t msg_size = 0, msg_len = 0;
442442
ly_bool use_err_app_tag = 0;
443443
struct lyplg_type *type_plg;
444444

@@ -465,16 +465,12 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct
465465
if (u == LYA_COUNT(type_u->types)) {
466466
/* create the full error */
467467
if (subvalue->format == LY_VALUE_LYB) {
468-
msg_len = asprintf(&msg, "Invalid LYB union value - no matching subtype found:\n");
468+
r = ly_append_str(&msg, &msg_size, &msg_len, "Invalid LYB union value - no matching subtype found:\n");
469469
} else {
470-
msg_len = asprintf(&msg, "Invalid union value \"%.*s\" - no matching subtype found:\n",
470+
r = ly_append_str(&msg, &msg_size, &msg_len, "Invalid union value \"%.*s\" - no matching subtype found:\n",
471471
(int)subvalue->orig_size_bits / 8, (char *)subvalue->original);
472472
}
473-
if (msg_len == -1) {
474-
LY_CHECK_ERR_GOTO(!errs, rc = LY_EMEM, cleanup);
475-
/* for further actions in function msg_len is just 0 */
476-
msg_len = 0;
477-
}
473+
LY_CHECK_ERR_GOTO(r, rc = LY_EMEM, cleanup);
478474
LYA_FOR(type_u->types, u) {
479475
if (!errs[u]) {
480476
/* no error for some reason */
@@ -494,9 +490,8 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct
494490

495491
type_plg = LYSC_GET_TYPE_PLG(type_u->types[u]->plugin_ref);
496492

497-
msg = ly_realloc(msg, msg_len + 4 + strlen(type_plg->id) + 2 + strlen(errs[u]->msg) + 2);
498-
LY_CHECK_ERR_GOTO(!msg, rc = LY_EMEM, cleanup);
499-
msg_len += sprintf(msg + msg_len, " %s: %s\n", type_plg->id, errs[u]->msg);
493+
r = ly_append_str(&msg, &msg_size, &msg_len, " %s: %s\n", type_plg->id, errs[u]->msg);
494+
LY_CHECK_ERR_GOTO(r, rc = LY_EMEM, cleanup);
500495
}
501496

502497
if (!use_err_app_tag) {

0 commit comments

Comments
 (0)