Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions src/parser-expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1468,12 +1468,21 @@ static void read_expr_operand_body(block_t *parent, basic_block_t **bb)
else if (lex_accept(T_decrement))
prefix_op = OP_sub;

lex_peek(T_identifier, token);

/* is a constant or variable? */
const constant_t *con = find_scoped_constant(token, parent);
var_t *var = find_var(token, parent);
func_t *func = find_visible_func(token, parent);
/* Only an identifier names a constant, variable or function. Any other
* token, such as the brace of an array literal, leaves the name empty
* and looks nothing up.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nonblocking documentation suggestion: explicitly connect the empty name to the built-in comparisons below. Guarding the lookups alone would still leave those strcmp() calls reading an uninitialized buffer, so the else is necessary.

For example:

/* Non-identifiers skip name lookup and use an empty name for the
 * built-in comparisons below.
 */

The current implementation is correct; this explains why both parts of the fix must stay together.

*/
const constant_t *con = NULL;
var_t *var = NULL;
func_t *func = NULL;

if (lex_peek(T_identifier, token)) {
con = find_scoped_constant(token, parent);
var = find_var(token, parent);
func = find_visible_func(token, parent);
} else {
token[0] = '\0';
}

/* A block-scope function prototype shadows an automatic object, but its
* designator is the file-scope function rather than an indirect call
Expand Down
10 changes: 10 additions & 0 deletions tests/driver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13049,6 +13049,16 @@ EOF

# Extended compound literal tests (C99-style brace initialization)

# An operand that opens with a brace is an array literal. It names nothing, so
# no identifier lookup may decide how it parses.
try_ 0 << EOF
int main(void)
{
long long v = {};
return (int) v;
}
EOF

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nonblocking: please add a compile-error regression for the other path this fix protects:

try_compile_error << EOF
int main(void) { return +; }
EOF

I verified that the unpatched compiler, built with -O0 -fwrapv -ftrivial-auto-var-init=pattern -fsanitize=address, overflows token in hashmap_hash() on this input. This patch instead reports Unrecognized expression token without an ASan overflow. The existing {} case covers successful parsing; this small case also covers malformed-input handling.


# Additional struct compound literals with different field counts
try_ 12 << EOF
typedef struct { int a; int b; int c; int d; } quad_t;
Expand Down