Skip to content

Fix a bunch of crashes discovered by fuzzing cppfront #1383

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 29, 2025
Merged
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
2 changes: 1 addition & 1 deletion include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ class contract_group {
std::cerr << ": " << msg;
}
std::cerr << "\n";
std::terminate();
std::exit(EXIT_FAILURE);
}

auto inline cpp2_default = contract_group(
Expand Down
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-error.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-error.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-error.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-error.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-error.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
*/
}
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-error.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
Expand Up @@ -80,56 +80,56 @@ In file included from pure2-expected-is-as.cpp:7:
../../../include/cpp2util.h:469:72: error: invalid application of 'sizeof' to a function type
(std::is_floating_point_v<From> && std::is_floating_point_v<To> && sizeof(From) > sizeof(To)) || // NOLINT(misc-redundant-expression)
^~~~~~~~~~~~
../../../include/cpp2util.h:2923:19: note: in instantiation of variable template specialization 'cpp2::impl::is_narrowing_v' requested here
../../../include/cpp2util.h:2924:19: note: in instantiation of variable template specialization 'cpp2::impl::is_narrowing_v' requested here
if constexpr (is_narrowing_v<C, CPP2_TYPEOF(x)>) {
^
pure2-expected-is-as.cpp2:39:28: note: in instantiation of function template specialization 'cpp2::impl::as_<int, double (&)(double) noexcept>' requested here
auto val1 {cpp2::impl::as_<int>(ex1)};
^
In file included from pure2-expected-is-as.cpp:7:
../../../include/cpp2util.h:2943:12: error: no matching function for call to 'as'
../../../include/cpp2util.h:2944:12: error: no matching function for call to 'as'
return as<C>(CPP2_FORWARD(x));
^~~~~
pure2-expected-is-as.cpp2:39:28: note: in instantiation of function template specialization 'cpp2::impl::as_<int, double (&)(double) noexcept>' requested here
auto val1 {cpp2::impl::as_<int>(ex1)};
^
../../../include/cpp2util.h:1901:16: note: candidate template ignored: constraints not satisfied [with C = int, x:auto = double (&)(double) noexcept]
../../../include/cpp2util.h:1902:16: note: candidate template ignored: constraints not satisfied [with C = int, x:auto = double (&)(double) noexcept]
constexpr auto as(auto&& x CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT_AS) -> decltype(auto)
^
../../../include/cpp2util.h:1907:18: note: because 'std::is_scalar_v<std::remove_cvref_t<decltype(x)> >' evaluated to false
../../../include/cpp2util.h:1908:18: note: because 'std::is_scalar_v<std::remove_cvref_t<decltype(x)> >' evaluated to false
(std::is_scalar_v<CPP2_TYPEOF(x)> && !std::is_enum_v<CPP2_TYPEOF(x)>)
^
../../../include/cpp2util.h:1908:17: note: and 'std::is_floating_point_v<std::remove_cvref_t<decltype(x)> >' evaluated to false
../../../include/cpp2util.h:1909:17: note: and 'std::is_floating_point_v<std::remove_cvref_t<decltype(x)> >' evaluated to false
|| std::is_floating_point_v<CPP2_TYPEOF(x)>
^
../../../include/cpp2util.h:1909:17: note: and 'std::is_base_of_v<int, std::remove_cvref_t<decltype(x)> >' evaluated to false
../../../include/cpp2util.h:1910:17: note: and 'std::is_base_of_v<int, std::remove_cvref_t<decltype(x)> >' evaluated to false
|| std::is_base_of_v<C, CPP2_TYPEOF(x)>
^
../../../include/cpp2util.h:1910:17: note: and 'std::is_base_of_v<std::remove_cvref_t<decltype(x)>, int>' evaluated to false
../../../include/cpp2util.h:1911:17: note: and 'std::is_base_of_v<std::remove_cvref_t<decltype(x)>, int>' evaluated to false
|| std::is_base_of_v<CPP2_TYPEOF(x), C>
^
../../../include/cpp2util.h:1911:30: note: and 'C({std::forward<decltype(x)>(x)})' would be invalid: cannot initialize a value of type 'int' with an lvalue of type 'double (double) noexcept'
../../../include/cpp2util.h:1912:30: note: and 'C({std::forward<decltype(x)>(x)})' would be invalid: cannot initialize a value of type 'int' with an lvalue of type 'double (double) noexcept'
|| requires { C{CPP2_FORWARD(x)}; }
^
../../../include/cpp2util.h:327:37: note: expanded from macro 'CPP2_FORWARD'
#define CPP2_FORWARD(x) std::forward<decltype(x)>(x)
^
../../../include/cpp2util.h:2040:6: note: candidate template ignored: constraints not satisfied [with C = int, X = double (&)(double) noexcept]
../../../include/cpp2util.h:2041:6: note: candidate template ignored: constraints not satisfied [with C = int, X = double (&)(double) noexcept]
auto as(X&& x CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT_AS) -> decltype(auto)
^
../../../include/cpp2util.h:2039:23: note: because 'specialization_of_template<double (&)(double) noexcept, std::variant>' evaluated to false
../../../include/cpp2util.h:2040:23: note: because 'specialization_of_template<double (&)(double) noexcept, std::variant>' evaluated to false
template< typename C, specialization_of_template<std::variant> X >
^
../../../include/cpp2util.h:891:7: note: because 'specialization_of_template_helper<C>(std::forward<X>(x))' would be invalid: no matching function for call to 'specialization_of_template_helper'
../../../include/cpp2util.h:892:7: note: because 'specialization_of_template_helper<C>(std::forward<X>(x))' would be invalid: no matching function for call to 'specialization_of_template_helper'
{ specialization_of_template_helper<C>(std::forward<X>(x)) } -> std::same_as<std::true_type>;
^
../../../include/cpp2util.h:2087:16: note: candidate template ignored: constraints not satisfied [with T = int, X = double (&)(double) noexcept]
../../../include/cpp2util.h:2088:16: note: candidate template ignored: constraints not satisfied [with T = int, X = double (&)(double) noexcept]
constexpr auto as( X && x ) -> decltype(auto) {
^
../../../include/cpp2util.h:2086:22: note: because 'same_type_as<double (&)(double) noexcept, std::any>' evaluated to false
../../../include/cpp2util.h:2087:22: note: because 'same_type_as<double (&)(double) noexcept, std::any>' evaluated to false
template<typename T, same_type_as<std::any> X>
^
../../../include/cpp2util.h:921:29: note: because 'std::same_as<std::remove_cvref_t<double (&)(double) noexcept>, std::remove_cvref_t<any> >' evaluated to false
../../../include/cpp2util.h:922:29: note: because 'std::same_as<std::remove_cvref_t<double (&)(double) noexcept>, std::remove_cvref_t<any> >' evaluated to false
concept same_type_as = std::same_as<std::remove_cvref_t<X>, std::remove_cvref_t<C>>;
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/concepts:63:19: note: because '__detail::__same_as<double (double) noexcept, std::any>' evaluated to false
Expand All @@ -138,19 +138,19 @@ concept same_type_as = std::same_as<std::remove_cvref_t<X>, std::remove_cvref_t<
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/concepts:57:27: note: because 'std::is_same_v<double (double) noexcept, std::any>' evaluated to false
concept __same_as = std::is_same_v<_Tp, _Up>;
^
../../../include/cpp2util.h:2130:16: note: candidate template ignored: constraints not satisfied [with T = int, X = double (&)(double) noexcept]
../../../include/cpp2util.h:2131:16: note: candidate template ignored: constraints not satisfied [with T = int, X = double (&)(double) noexcept]
constexpr auto as( X&& x ) -> decltype(auto) {
^
../../../include/cpp2util.h:2129:22: note: because 'specialization_of_template<double (&)(double) noexcept, std::optional>' evaluated to false
../../../include/cpp2util.h:2130:22: note: because 'specialization_of_template<double (&)(double) noexcept, std::optional>' evaluated to false
template<typename T, specialization_of_template<std::optional> X>
^
../../../include/cpp2util.h:891:7: note: because 'specialization_of_template_helper<C>(std::forward<X>(x))' would be invalid: no matching function for call to 'specialization_of_template_helper'
../../../include/cpp2util.h:892:7: note: because 'specialization_of_template_helper<C>(std::forward<X>(x))' would be invalid: no matching function for call to 'specialization_of_template_helper'
{ specialization_of_template_helper<C>(std::forward<X>(x)) } -> std::same_as<std::true_type>;
^
../../../include/cpp2util.h:1876:16: note: candidate function template not viable: requires 0 arguments, but 1 was provided
../../../include/cpp2util.h:1877:16: note: candidate function template not viable: requires 0 arguments, but 1 was provided
constexpr auto as() -> auto
^
../../../include/cpp2util.h:1887:16: note: candidate function template not viable: requires 0 arguments, but 1 was provided
../../../include/cpp2util.h:1888:16: note: candidate function template not viable: requires 0 arguments, but 1 was provided
constexpr auto as() -> auto
^
pure2-expected-is-as.cpp2:39:37: error: use of undeclared identifier 'ex1'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mixed-bugfix-for-double-pound-else-error.cpp2...
mixed-bugfix-for-double-pound-else-error.cpp2(2,1): error: #else does not match a prior #if
mixed-bugfix-for-double-pound-else-error.cpp2(3,1): error: #else does not match a prior #if
mixed-bugfix-for-double-pound-else-error.cpp2(3,1): error: #else already encountered for this #if

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pure2-bugfix-for-late-comments.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pure2-bugfix-for-assert-capture-error.cpp2...
pure2-bugfix-for-assert-capture-error.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-error.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-error.cpp2...
pure2-bugfix-for-bad-capture-error.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-error.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-error.cpp2...
pure2-bugfix-for-bad-decltype-error.cpp2(3,14): error: 'decltype' must be followed by a single parenthesized expression
pure2-bugfix-for-bad-decltype-error.cpp2(3,24): error: 'is' must be followed by a type-id or an expression
pure2-bugfix-for-bad-decltype-error.cpp2(3,14): error: 'decltype' must be followed by a single parenthesized expression
pure2-bugfix-for-bad-decltype-error.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-error.cpp2...
pure2-bugfix-for-bad-parameter-error.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-error.cpp2...
pure2-bugfix-for-functions-before-superclasses-error.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-error.cpp2...
pure2-bugfix-for-invalid-alias-error.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-error.cpp2...
pure2-bugfix-for-naked-unsigned-char-error.cpp2(2,8): error: 'unsigned char' - did you mean 'u8' (usually best) or 'cpp2::_uchar'?
pure2-bugfix-for-naked-unsigned-char-error.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-error.cpp2...
pure2-bugfix-for-namespace-error.cpp2(2,22): error: types cannot contain namespaces (at 'namespace')

16 changes: 13 additions & 3 deletions source/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,12 @@ 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 +472,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
22 changes: 13 additions & 9 deletions source/lex.h
Original file line number Diff line number Diff line change
Expand Up @@ -713,13 +713,19 @@ 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 +756,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
Loading
Loading