Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix a bunch of crashes discovered by fuzzing cppfront #1383

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
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
3 changes: 2 additions & 1 deletion include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,8 @@ class contract_group {
std::cerr << ": " << msg;
}
std::cerr << "\n";
std::terminate();
// Get outta here but don't raise a signal
std::exit(1);
}

auto inline cpp2_default = contract_group(
Expand Down
2 changes: 2 additions & 0 deletions regression-tests/mixed-bugfix-for-double-poundelse.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#else
#else
3 changes: 3 additions & 0 deletions regression-tests/pure2-bugfix-for-assert-capture.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
crash_10: (foo: i32) = {
assert( 10LL as i32 == foo$);
}
3 changes: 3 additions & 0 deletions regression-tests/pure2-bugfix-for-bad-capture.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
crash_10: (foo: i32) = {
assert( 10LL as i32 == foo$);
}
4 changes: 4 additions & 0 deletions regression-tests/pure2-bugfix-for-bad-decltype.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
crash_89: () = {
f := new<int>(0);
_ = f is decltype.f);
}
1 change: 1 addition & 0 deletions regression-tests/pure2-bugfix-for-bad-parameter.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print: <T: type> (inout out: std::ostream=args: T) requires true = {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
crash_m0b: type = {
}

crash_m0c: type = {
name: i32;
get_name: (this) -> i32 = { return name; }
this: crash_m0b;
}
3 changes: 3 additions & 0 deletions regression-tests/pure2-bugfix-for-invalid-alias.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
outer: type = {
x: requires true == 42;
}
11 changes: 11 additions & 0 deletions regression-tests/pure2-bugfix-for-late-comments.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

main: () -> int = {
x := crash_m0();
_ = x;
}

crash_m0: type = {
operator-: (this, _) -> int = 0;/* Comment starts here
And continues here
*/
}
3 changes: 3 additions & 0 deletions regression-tests/pure2-bugfix-for-naked-unsigned-char.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
main: () = {
e: unsigned char
}
9 changes: 9 additions & 0 deletions regression-tests/pure2-bugfix-for-namespace.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
crash_96: @print type = {
namespace_alias: namespace = type_alias: type == array<int,10>;
}

crash_96a: @print type = {
test: () = {
namespace_alias: namespace = type_alias: type == array<int,10>;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mixed-bugfix-for-double-poundelse.cpp2...
mixed-bugfix-for-double-poundelse.cpp2(2,1): error: #else does not match a prior #if
mixed-bugfix-for-double-poundelse.cpp2(3,1): error: #else does not match a prior #if
mixed-bugfix-for-double-poundelse.cpp2(3,1): error: #else already encountered for this #if

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pure2-bugfix-for-assert-capture.cpp2...
pure2-bugfix-for-assert-capture.cpp2(2,29): error: $ (capture) cannot appear here - it must appear in an anonymous expression function, a postcondition, or an interpolated string literal (at '$')
pure2-bugfix-for-assert-capture.cpp2(2,23): error: expected ')' at the end of the contract (at '==')

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pure2-bugfix-for-bad-capture.cpp2...
pure2-bugfix-for-bad-capture.cpp2(2,29): error: $ (capture) cannot appear here - it must appear in an anonymous expression function, a postcondition, or an interpolated string literal (at '$')
pure2-bugfix-for-bad-capture.cpp2(2,23): error: expected ')' at the end of the contract (at '==')

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pure2-bugfix-for-bad-decltype.cpp2...
pure2-bugfix-for-bad-decltype.cpp2(3,14): error: 'decltype' must be followed by a single parenthesized expression
pure2-bugfix-for-bad-decltype.cpp2(3,24): error: 'is' must be followed by a type-id or an expression
pure2-bugfix-for-bad-decltype.cpp2(3,14): error: 'decltype' must be followed by a single parenthesized expression
pure2-bugfix-for-bad-decltype.cpp2(3,24): error: 'is' must be followed by a type-id or an expression

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pure2-bugfix-for-bad-parameter.cpp2...
pure2-bugfix-for-bad-parameter.cpp2(1,50): error: parameter must be initialized with an expression (at ')')

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pure2-bugfix-for-functions-before-superclasses.cpp2...
pure2-bugfix-for-functions-before-superclasses.cpp2(7,3): error: a type cannot declare a parent after defining a function

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pure2-bugfix-for-invalid-alias.cpp2...
pure2-bugfix-for-invalid-alias.cpp2(2,25): error: invalid alias declaration - expected 'type', 'namespace', or a type-id after ':'

47 changes: 47 additions & 0 deletions regression-tests/test-results/pure2-bugfix-for-late-comments.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@

#define CPP2_IMPORT_STD Yes

//=== Cpp2 type declarations ====================================================


#include "cpp2util.h"

#line 1 "pure2-bugfix-for-late-comments.cpp2"

#line 7 "pure2-bugfix-for-late-comments.cpp2"
class crash_m0;


//=== Cpp2 type definitions and function declarations ===========================

#line 1 "pure2-bugfix-for-late-comments.cpp2"

#line 2 "pure2-bugfix-for-late-comments.cpp2"
[[nodiscard]] auto main() -> int;

#line 7 "pure2-bugfix-for-late-comments.cpp2"
class crash_m0 {
public: [[nodiscard]] auto operator-([[maybe_unused]] auto const& unnamed_param_2) const& -> int;
public: crash_m0() = default;
public: crash_m0(crash_m0 const&) = delete; /* No 'that' constructor, suppress copy */
public: auto operator=(crash_m0 const&) -> void = delete;


#line 11 "pure2-bugfix-for-late-comments.cpp2"
};


//=== Cpp2 function definitions =================================================

#line 1 "pure2-bugfix-for-late-comments.cpp2"

#line 2 "pure2-bugfix-for-late-comments.cpp2"
[[nodiscard]] auto main() -> int{
auto x {crash_m0()};
static_cast<void>(cpp2::move(x));
}

#line 8 "pure2-bugfix-for-late-comments.cpp2"
[[nodiscard]] auto crash_m0::operator-([[maybe_unused]] auto const& unnamed_param_2) const& -> int { return 0; }/* Comment starts here
And continues here
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pure2-bugfix-for-late-comments.cpp2... ok (all Cpp2, passes safety checks)

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pure2-bugfix-for-naked-unsigned-char.cpp2...
pure2-bugfix-for-naked-unsigned-char.cpp2(2,8): error: 'unsigned char' - did you mean 'u8' (usually best) or 'cpp2::_uchar'?
pure2-bugfix-for-naked-unsigned-char.cpp2(2,8): error: 'unsigned char' is an old-style C/C++ multi-word keyword type
- most such types should be used only for interoperability with older code
- using those when you need them is fine, but name them with these short names instead:
short, ushort, int, uint, long, ulong, longlong, ulonglong, longdouble, _schar, _uchar
- see also cpp2util.h > "Convenience names for integer types"

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pure2-bugfix-for-namespace.cpp2...
pure2-bugfix-for-namespace.cpp2(2,22): error: types cannot contain namespaces (at 'namespace')

15 changes: 12 additions & 3 deletions source/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,11 @@ class braces_tracker
else { --else_net_braces; }
}

auto found_preprocessor_else() -> void {
assert (!found_else);
auto found_preprocessor_else_was_there_another() -> bool {
if (found_else)
return true;
found_else = true;
return false;
}

// If the "if" and "else" branches opened/closed the same net number
Expand Down Expand Up @@ -469,7 +471,14 @@ class braces_tracker
);
}

preprocessor.back().found_preprocessor_else();
if (preprocessor.back().found_preprocessor_else_was_there_another()) {
// If this is the second or subsequent #else, it doesn't match
// the prior #if, so report an error
errors.emplace_back(
lineno,
"#else already encountered for this #if"
);
};
}

// Exiting an #endif
Expand Down
21 changes: 12 additions & 9 deletions source/lex.h
Original file line number Diff line number Diff line change
Expand Up @@ -713,13 +713,18 @@ auto lex_line(
tokens.pop_back();
++num_merged_tokens;
}

tokens.push_back({
&generated_text.back()[0],
std::ssize(generated_text.back()),
pos,
lexeme::Keyword
});

// It's an error to have more than one of these, but we require that
// the number of tokens has not gone down. So just push back as many
// tokens as we merged. This will ensure that the token count remains
// the same.
for (auto i = 0; i < num_merged_tokens; i++)
tokens.push_back({
&generated_text.back()[0],
std::ssize(generated_text.back()),
pos,
lexeme::Keyword
});

if (num_merged_tokens > 1)
{
Expand Down Expand Up @@ -750,8 +755,6 @@ auto lex_line(
" short, ushort, int, uint, long, ulong, longlong, ulonglong, longdouble, _schar, _uchar\n"
" - see also cpp2util.h > \"Convenience names for integer types\""
);

return;
}

tokens.push_back(last_token);
Expand Down
36 changes: 31 additions & 5 deletions source/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -5956,7 +5956,7 @@ auto pretty_print_visualize(
+ initializer;
}
else if (n.is_namespace()) {
auto& t = std::get<declaration_node::a_type>(n.type);
auto& t = std::get<declaration_node::a_namespace>(n.type);
assert(t);
ret += "namespace = "
+ initializer;
Expand Down Expand Up @@ -7253,6 +7253,7 @@ class parser
if (auto id = postfix_expression();
id
&& id->ops.size() == 1
&& id->ops[0].expr_list
&& id->ops[0].expr_list->expressions.size() == 1
&& id->ops[0].expr_list->open_paren->type() == lexeme::LeftParen
)
Expand Down Expand Up @@ -8683,6 +8684,18 @@ class parser
}
}

if (
!is_returns
&& n->declaration->initializer
&& !n->declaration->initializer->is_expression()
)
{
// If the initializer is not an expression statement (like a function call),
// then it can't be used as a parameter.
error("parameter must be initialized with an expression");
return {};
}

return n;
}

Expand Down Expand Up @@ -8805,7 +8818,6 @@ class parser
-> std::unique_ptr<contract_node>
{
auto n = std::make_unique<contract_node>(curr().position());
auto guard = capture_groups_stack_guard(this, &n->captures);

if (
curr() != "pre"
Expand All @@ -8816,6 +8828,13 @@ class parser
return {};
}
n->kind = &curr();

auto guard =
curr() == "post"
? std::make_unique<capture_groups_stack_guard>(this, &n->captures)
: std::unique_ptr<capture_groups_stack_guard>()
;

next();

// Check if there's a <group,flags>
Expand Down Expand Up @@ -9292,6 +9311,10 @@ class parser
// Or a namespace
else if (curr() == "namespace")
{
if (n->parent_is_type()) {
error("types cannot contain namespaces");
return {};
}
n->type = std::make_unique<namespace_node>( &curr() );
assert (n->type.index() == declaration_node::a_namespace);
next();
Expand Down Expand Up @@ -9824,10 +9847,13 @@ class parser
a->initializer = std::move(e);
}

// Anything else shouldn't be possible
// Anything else is illegal
else {
assert(false && "ICE: should be unreachable - invalid alias declaration");
return {};
errors.emplace_back(
curr().position(),
"invalid alias declaration - expected 'type', 'namespace', or a type-id after ':'"
);
return {};
}

// And the final ceremonial semicolon
Expand Down
19 changes: 19 additions & 0 deletions source/sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2037,6 +2037,7 @@ class sema
if (n.is_type()) {
auto compound_stmt = n.initializer->get_if<compound_statement_node>();
assert (compound_stmt);
bool seen_function = false;
for (auto& stmt : compound_stmt->statements) {
if (
!stmt->is_declaration()
Expand All @@ -2049,6 +2050,24 @@ class sema
);
return false;
}
auto stmt_decl = stmt->get_if<declaration_node>();
// If this is a declaration, check if it's a function
if (stmt_decl && stmt_decl->is_function())
seen_function = true;

// If this is called 'this', then make sure we haven't seen any functions
if (
stmt_decl
&& stmt_decl->has_name("this")
&& seen_function
)
{
handle_error(
stmt->position(),
"a type cannot declare a parent after defining a function"
);
return false;
}
}
}

Expand Down
12 changes: 8 additions & 4 deletions source/to_cpp1.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ class positional_printer
c.dbg_was_printed = true;
}

auto flush_comments( source_position pos )
auto flush_comments( source_position pos, bool print_remaining_comments = false )
-> void
{
if (!pcomments) {
Expand All @@ -444,7 +444,7 @@ class positional_printer

// Add unprinted comments and blank lines as needed to catch up vertically
//
while (curr_pos.lineno < pos.lineno)
while (print_remaining_comments ? (next_comment < std::ssize(comments)) : (curr_pos.lineno < pos.lineno))
{
// If a comment goes on this line, print it
if (
Expand All @@ -468,7 +468,8 @@ class positional_printer
)
{
print_comment( comments[next_comment] );
assert(curr_pos.lineno <= pos.lineno); // we shouldn't have overshot
if (!print_remaining_comments)
assert(curr_pos.lineno <= pos.lineno); // we shouldn't have overshot
}

++next_comment;
Expand All @@ -479,6 +480,9 @@ class positional_printer
print("\n");
}
}
// And catch up.
while (curr_pos.lineno < pos.lineno)
print("\n");
}

auto print_unprinted_comments()
Expand Down Expand Up @@ -589,7 +593,7 @@ class positional_printer
&& psource->has_cpp2()
)
{
flush_comments( {curr_pos.lineno+1, 1} );
flush_comments( {curr_pos.lineno+1, 1}, print_remaining_comments );

if (print_remaining_comments) {
print_unprinted_comments();
Expand Down