Skip to content

Commit

Permalink
tools: ynl-gen: improve unwind on parsing errors
Browse files Browse the repository at this point in the history
When parsing multi-attr we count the objects and then allocate
an array to hold the parsed objects. If an attr space has multiple
multi-attr objects, however, if parsing the first array fails
we'll leave the object count for the second even tho the second
array was never allocated.

This may cause crashes when freeing objects on error.

Count attributes to a variable on the stack and only set the count
in the object once the memory was allocated.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Jun 7, 2023
1 parent 2cc9671 commit 58da455
Showing 1 changed file with 17 additions and 5 deletions.
22 changes: 17 additions & 5 deletions tools/net/ynl/ynl-gen-c.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ def _attr_typol(self):
raise Exception(f"Sub-type {self.attr['type']} not supported yet")

def _attr_get(self, ri, var):
return f'{var}->n_{self.c_name}++;', None, None
return f'n_{self.c_name}++;', None, None

def attr_put(self, ri, var):
if self.attr['type'] in scalars:
Expand Down Expand Up @@ -1306,6 +1306,11 @@ def _multi_parse(ri, struct, init_lines, local_vars):
local_vars.append('struct ynl_parse_arg parg;')
init_lines.append('parg.ys = yarg->ys;')

all_multi = array_nests | multi_attrs

for anest in sorted(all_multi):
local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;")

ri.cw.block_start()
ri.cw.write_func_lvar(local_vars)

Expand All @@ -1316,6 +1321,11 @@ def _multi_parse(ri, struct, init_lines, local_vars):
for arg in struct.inherited:
ri.cw.p(f'dst->{arg} = {arg};')

for anest in sorted(all_multi):
aspec = struct[anest]
ri.cw.p(f"if (dst->{aspec.c_name})")
ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");')

ri.cw.nl()
ri.cw.block_start(line=iter_line)

Expand All @@ -1331,8 +1341,9 @@ def _multi_parse(ri, struct, init_lines, local_vars):
for anest in sorted(array_nests):
aspec = struct[anest]

ri.cw.block_start(line=f"if (dst->n_{aspec.c_name})")
ri.cw.p(f"dst->{aspec.c_name} = calloc(dst->n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
ri.cw.block_start(line=f"if (n_{aspec.c_name})")
ri.cw.p(f"dst->{aspec.c_name} = calloc({aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
ri.cw.p('i = 0;')
ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
ri.cw.block_start(line=f"mnl_attr_for_each_nested(attr, attr_{aspec.c_name})")
Expand All @@ -1346,8 +1357,9 @@ def _multi_parse(ri, struct, init_lines, local_vars):

for anest in sorted(multi_attrs):
aspec = struct[anest]
ri.cw.block_start(line=f"if (dst->n_{aspec.c_name})")
ri.cw.p(f"dst->{aspec.c_name} = calloc(dst->n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
ri.cw.block_start(line=f"if (n_{aspec.c_name})")
ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
ri.cw.p('i = 0;')
if 'nested-attributes' in aspec:
ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
Expand Down

0 comments on commit 58da455

Please sign in to comment.