From 6acd68264cbed8d70896016fda7568dd42be78c2 Mon Sep 17 00:00:00 2001 From: Sophie Tyalie Date: Mon, 31 Oct 2022 17:08:13 +0100 Subject: [PATCH] Fix: c_parser ignored scopes with nameless inline struct The `parse_type` would continue looking for tokens even when the c_type ended with a `{`. This would mean that the following resulted in an exception: ``` __struct__ = """ struct { int i; } s; """ ``` `parse_type` now ignores any following tokens if `c_type` ends with an `{` - meaning the tokens afterwards are not element of the current type scope. Signed-off-by: Sophie Tyalie --- cstruct/c_parser.py | 72 +++++++++++++++++++++++-------------------- tests/test_cstruct.py | 5 ++- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/cstruct/c_parser.py b/cstruct/c_parser.py index d1a947c..476067a 100644 --- a/cstruct/c_parser.py +++ b/cstruct/c_parser.py @@ -78,43 +78,47 @@ def parse_type(tokens: Tokens, __cls__: Type['AbstractCStruct'], byte_order: Opt # signed/unsigned/struct if c_type in ['signed', 'unsigned', 'struct', 'union'] and len(tokens) > 1: c_type = c_type + " " + tokens.pop() - next_token = tokens.pop() - # short int, long int, or long long - if next_token in ['int', 'long']: - c_type = c_type + " " + next_token - next_token = tokens.pop() - # void * - if next_token.startswith("*"): - next_token = next_token[1:] - c_type = 'void *' - # parse length + vlen = 1 flexible_array = False - if "[" in next_token: - t = next_token.split("[") - if len(t) != 2: - raise ParserError("Error parsing: " + next_token) - next_token = t[0].strip() - vlen_part = t[1] - vlen_expr = [] - while not vlen_part.endswith("]"): + + if not c_type.endswith("{"): + next_token = tokens.pop() + # short int, long int, or long long + if next_token in ['int', 'long']: + c_type = c_type + " " + next_token + next_token = tokens.pop() + # void * + if next_token.startswith("*"): + next_token = next_token[1:] + c_type = 'void *' + # parse length + if "[" in next_token: + t = next_token.split("[") + if len(t) != 2: + raise ParserError("Error parsing: " + next_token) + next_token = t[0].strip() + vlen_part = t[1] + vlen_expr = [] + while not vlen_part.endswith("]"): + vlen_expr.append(vlen_part.split("]")[0].strip()) + vlen_part = tokens.pop() + t_vlen = vlen_part.split("]")[0].strip() vlen_expr.append(vlen_part.split("]")[0].strip()) - vlen_part = tokens.pop() - t_vlen = vlen_part.split("]")[0].strip() - vlen_expr.append(vlen_part.split("]")[0].strip()) - t_vlen = " ".join(vlen_expr) - if not t_vlen: - flexible_array = True - vlen = 0 - else: - try: - vlen = c_eval(t_vlen) - except (ValueError, TypeError): - vlen = int(t_vlen) - tokens.push(next_token) - # resolve typedefs - while c_type in TYPEDEFS: - c_type = TYPEDEFS[c_type] + t_vlen = " ".join(vlen_expr) + if not t_vlen: + flexible_array = True + vlen = 0 + else: + try: + vlen = c_eval(t_vlen) + except (ValueError, TypeError): + vlen = int(t_vlen) + tokens.push(next_token) + # resolve typedefs + while c_type in TYPEDEFS: + c_type = TYPEDEFS[c_type] + # calculate fmt if c_type.startswith('struct ') or c_type.startswith('union '): # struct/union c_type, tail = c_type.split(' ', 1) diff --git a/tests/test_cstruct.py b/tests/test_cstruct.py index cd7350b..a3653a1 100644 --- a/tests/test_cstruct.py +++ b/tests/test_cstruct.py @@ -75,10 +75,12 @@ class MBR(cstruct.CStruct): class Dummy(cstruct.CStruct): __byte_order__ = cstruct.LITTLE_ENDIAN __def__ = """ + struct { struct { + int i; + } s; char c; char vc[10]; - int i; int vi[10]; long long l; long vl[10]; @@ -210,6 +212,7 @@ def test_inline(): def test_dummy(): dummy = Dummy() + dummy.c = b'A' dummy.vc = b'ABCDEFGHIJ' dummy.i = 123456