diff --git a/SECURITY.md b/SECURITY.md index 26253985..3d78dd99 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,6 +8,8 @@ the `master` branch. ## Reporting a Vulnerability -To report a security issue, please disclose it at [security advisory](https://github.com/eliben/pycparser/security/advisories/new). +We don't consider pycparser to be a project suitable to be used at a security +boundary. Please don't use it as such. -We will respond within 14 working days of your submission. If the issue is confirmed as a vulnerability, we will open a Security Advisory and acknowledge your contributions as part of it. This project follows a 90 day disclosure timeline. +If you found what you believe to be a security issue with pycparser, feel free +to open a public GitHub issue or email the project's maintainer. diff --git a/pycparser/_c_ast.cfg b/pycparser/_c_ast.cfg index 0626533e..abb15d28 100644 --- a/pycparser/_c_ast.cfg +++ b/pycparser/_c_ast.cfg @@ -107,6 +107,9 @@ FileAST: [ext**] # For: [init*, cond*, next*, stmt*] +GenericSelection: [expr*, assoc_list**] +GenericAssociation: [type*, expr*] + # name: Id # args: ExprList # diff --git a/pycparser/c_ast.py b/pycparser/c_ast.py index 36363230..9448afa5 100644 --- a/pycparser/c_ast.py +++ b/pycparser/c_ast.py @@ -1128,3 +1128,33 @@ def __iter__(self): attr_names = ('string', ) +class GenericAssociation(Node): + __slots__ = ('type', 'expr', 'coord', '__weakref__') + def __init__(self, type, expr, coord=None): + self.type = type + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(("type", self.type)) + if self.expr is not None: nodelist.append(("expr", self.expr)) + return tuple(nodelist) + + attr_names = () + +class GenericSelection(Node): + __slots__ = ('expr', 'assoc_list', 'coord', '__weakref__') + def __init__(self, expr, assoc_list, coord=None): + self.expr = expr + self.assoc_list = assoc_list + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(("expr", self.expr)) + for i, child in enumerate(self.assoc_list or []): + nodelist.append(("assoc_list[%d]" % i, child)) + return tuple(nodelist) + + attr_names = () \ No newline at end of file diff --git a/pycparser/c_lexer.py b/pycparser/c_lexer.py index 135826d1..3966dcb8 100644 --- a/pycparser/c_lexer.py +++ b/pycparser/c_lexer.py @@ -113,6 +113,7 @@ def _make_tok_location(self, token): '_NORETURN', '_THREAD_LOCAL', '_STATIC_ASSERT', '_ATOMIC', '_ALIGNOF', '_ALIGNAS', '_PRAGMA', + '_GENERIC', ) keyword_map = {} diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py index bb123ac7..80927e00 100644 --- a/pycparser/c_parser.py +++ b/pycparser/c_parser.py @@ -1835,6 +1835,30 @@ def p_primary_expression_5(self, p): p[0] = c_ast.FuncCall(c_ast.ID(p[1], coord), c_ast.ExprList([p[3], p[5]], coord), coord) + + def p_primary_expression_6(self, p): + """ primary_expression : generic_selection """ + p[0] = p[1] + + def p_generic_selection(self, p): + """ generic_selection : _GENERIC LPAREN assignment_expression COMMA generic_assoc_list RPAREN """ + p[0] = c_ast.GenericSelection(p[3], p[5], self._token_coord(p, 1)) + + def p_generic_assoc_list_1(self, p): + """ generic_assoc_list : generic_association """ + p[0] = [p[1]] + + def p_generic_assoc_list_2(self, p): + """ generic_assoc_list : generic_assoc_list COMMA generic_association """ + p[0] = p[1] + [p[3]] + + def p_generic_association_1(self, p): + """ generic_association : type_name COLON assignment_expression """ + p[0] = c_ast.GenericAssociation(p[1], p[3], p[1].coord) + + def p_generic_association_2(self, p): + """ generic_association : DEFAULT COLON assignment_expression """ + p[0] = c_ast.GenericAssociation(None, p[3], self._token_coord(p, 1)) def p_offsetof_member_designator(self, p): """ offsetof_member_designator : identifier