On Mon, Jun 30, 2025 at 07:58:49AM -0700, Stephen Hemminger wrote: > When compiled with Link Time Optimization, the existing code > generated an error, because the compiler was unable to intuit > that there was space in the flexible array. > > In function ‘test_argparse_copy’, > inlined from ‘test_argparse_init_obj’ at > ../app/test/test_argparse.c:108:2, > inlined from ‘test_argparse_opt_callback_parse_int_of_no_val’ at > ../app/test/test_argparse.c:490:8: > ../app/test/test_argparse.c:96:17: warning: ‘memcpy’ writing 56 bytes into a > region of size 0 overflows the destination [-Wstringop-overflow=] > 96 | memcpy(&dst->args[i], &src->args[i], > sizeof(src->args[i])); > > Initialiizing a structure with flexible array is special case > and compiler expands the structure to fit. But inside the copy > function it no longer knew that. > > The workaround is to put the copy inside the same function > and use structure assignment. Also macro should be uppper case. > > Fixes: 6c5c6571601c ("argparse: verify argument config") > Cc: fengcheng...@huawei.com > > Signed-off-by: Stephen Hemminger <step...@networkplumber.org> > --- > v2 - simpler fix is to just inline the copy > > app/test/test_argparse.c | 31 +++++++++++++++---------------- > 1 file changed, 15 insertions(+), 16 deletions(-) >
LGTM. One suggestion inline, in case you feel like adjusting things further. Acked-by: Bruce Richardson <bruce.richard...@intel.com> > diff --git a/app/test/test_argparse.c b/app/test/test_argparse.c > index 0a229752fa..d5b777e321 100644 > --- a/app/test/test_argparse.c > +++ b/app/test/test_argparse.c > @@ -71,7 +71,7 @@ test_argparse_callback(uint32_t index, const char *value, > void *opaque) > } > > /* valid templater, must contain at least two args. */ > -#define argparse_templater() { \ > +#define ARGPARSE_TEMPLATE { \ > .prog_name = "test_argparse", \ > .usage = "-a xx -b yy", \ > .descriptor = NULL, \ > @@ -87,25 +87,24 @@ test_argparse_callback(uint32_t index, const char *value, > void *opaque) > }, \ > } > > -static void > -test_argparse_copy(struct rte_argparse *dst, struct rte_argparse *src) > -{ > - uint32_t i; > - memcpy(dst, src, sizeof(*src)); > - for (i = 0; /* NULL */; i++) { > - memcpy(&dst->args[i], &src->args[i], sizeof(src->args[i])); > - if (src->args[i].name_long == NULL) > - break; > - } > -} > > static struct rte_argparse * > test_argparse_init_obj(void) > { > - static struct rte_argparse backup = argparse_templater(); > - static struct rte_argparse obj = argparse_templater(); > - /* Because obj may be overwritten, do a deep copy. */ > - test_argparse_copy(&obj, &backup); > + /* Note: initialization of structure with flexible arrary > + * increases the size of the variable to match. > + */ > + static const struct rte_argparse backup = ARGPARSE_TEMPLATE; > + static struct rte_argparse obj = ARGPARSE_TEMPLATE; > + unsigned int i; > + > + obj = backup; > + for (i = 0; ; i++) { > + obj.args[i] = backup.args[i]; > + if (backup.args[i].name_long == NULL) > + break; > + } We should consider either making this a "do { } while" loop or adding the termination condition to the "for" loop statement as normal. For example: unsigned int i = 0; obj = backup; do { obj.args[i] = backup.args[i]; } while (backup.args[++i].name_long != NULL); or else: obj = backup; for (i = 0; backup.args[i].name_long != NULL; i++) obj.args[i] = backup.args[i]; obj.args[i] = ARGPARSE_ARG_END(); I'd tend toward the second, myself, but what is in your patch above is fine as-is too. > + > return &obj; > } > > -- > 2.47.2 >