summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2023-06-06 22:43:01 +0300
committerJakub Kicinski <kuba@kernel.org>2023-06-07 22:53:10 +0300
commit58da455b31baf87dd74b71fc54d0356e05c0bf49 (patch)
treea16642c51d329b448b9a873cd5a41784df22d2bb
parent2cc9671a82e3ba8911f01b04fd8f8f2da3a238a7 (diff)
downloadlinux-58da455b31baf87dd74b71fc54d0356e05c0bf49.tar.xz
tools: ynl-gen: improve unwind on parsing errors
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>
-rwxr-xr-xtools/net/ynl/ynl-gen-c.py22
1 files changed, 17 insertions, 5 deletions
diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index 0a043edf5e03..c07340715601 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -488,7 +488,7 @@ class TypeMultiAttr(Type):
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:
@@ -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)
@@ -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)
@@ -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})")
@@ -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;")