]> www.infradead.org Git - users/hch/misc.git/commitdiff
tools: ynl: avoid "use of uninitialized variable" false positive in generated code
authorVladimir Oltean <vladimir.oltean@nxp.com>
Mon, 15 Sep 2025 14:44:14 +0000 (17:44 +0300)
committerJakub Kicinski <kuba@kernel.org>
Tue, 16 Sep 2025 15:12:20 +0000 (08:12 -0700)
With indexed-array types such as "ops" from
Documentation/netlink/specs/nlctrl.yaml, the generator creates code
such as:

int nlctrl_getfamily_rsp_parse(const struct nlmsghdr *nlh,
       struct ynl_parse_arg *yarg)
{
struct nlctrl_getfamily_rsp *dst;
const struct nlattr *attr_ops;
const struct nlattr *attr;
struct ynl_parse_arg parg;
unsigned int n_ops = 0;
int i;

...

ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len) {
unsigned int type = ynl_attr_type(attr);

if (type == CTRL_ATTR_FAMILY_ID) {
...
} else if (type == CTRL_ATTR_OPS) {
const struct nlattr *attr2;

attr_ops = attr;
ynl_attr_for_each_nested(attr2, attr) {
if (ynl_attr_validate(yarg, attr2))
return YNL_PARSE_CB_ERROR;
n_ops++;
}
} else {
...
}
}
if (n_ops) {
dst->ops = calloc(n_ops, sizeof(*dst->ops));
dst->_count.ops = n_ops;
i = 0;
parg.rsp_policy = &nlctrl_op_attrs_nest;
ynl_attr_for_each_nested(attr, attr_ops) {
...
}
}

return YNL_PARSE_CB_OK;
}

It is clear that due to the sequential nature of code execution, when
n_ops (initially zero) is incremented, attr_ops is also assigned from
the value of "attr" (the current iterator).

But some compilers, like gcc version 12.2.0 (Debian 12.2.0-14+deb12u1)
as distributed by Debian Bookworm, seem to be not sophisticated enough
to see this, and fail to compile (warnings treated as errors):

In file included from ../lib/ynl.h:10,
                 from nlctrl-user.c:9:
In function ‘ynl_attr_data_end’,
    inlined from ‘nlctrl_getfamily_rsp_parse’ at nlctrl-user.c:427:3:
../lib/ynl-priv.h:209:44: warning: ‘attr_ops’ may be used uninitialized [-Wmaybe-uninitialized]
  209 |         return (char *)ynl_attr_data(attr) + ynl_attr_data_len(attr);
      |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
nlctrl-user.c: In function ‘nlctrl_getfamily_rsp_parse’:
nlctrl-user.c:341:30: note: ‘attr_ops’ was declared here
  341 |         const struct nlattr *attr_ops;
      |                              ^~~~~~~~

It is a pity that we have to do this, but I see no other way than to
suppress the false positive by appeasing the compiler and initializing
the "*attr_{aspec.c_name}" variable with a bogus value (NULL). This will
never be used - at runtime it will always be overwritten when
"n_{struct[anest].c_name}" is non-zero.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20250915144414.1185788-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
tools/net/ynl/pyynl/ynl_gen_c.py

index 101d8ba9626f238a82cddd0bbc10bb4399e2ab22..0bb6530f64b856411407b812b84006405aa473d5 100755 (executable)
@@ -2106,10 +2106,10 @@ def _multi_parse(ri, struct, init_lines, local_vars):
     for arg, aspec in struct.member_list():
         if aspec['type'] == 'indexed-array' and 'sub-type' in aspec:
             if aspec["sub-type"] in {'binary', 'nest'}:
-                local_vars.append(f'const struct nlattr *attr_{aspec.c_name};')
+                local_vars.append(f'const struct nlattr *attr_{aspec.c_name} = NULL;')
                 array_nests.add(arg)
             elif aspec['sub-type'] in scalars:
-                local_vars.append(f'const struct nlattr *attr_{aspec.c_name};')
+                local_vars.append(f'const struct nlattr *attr_{aspec.c_name} = NULL;')
                 array_nests.add(arg)
             else:
                 raise Exception(f'Not supported sub-type {aspec["sub-type"]}')