compiler, runtime: provide index information on bounds check failure

This implements https://golang.org/cl/161477 in the gofrontend.
    
    Updates golang/go#30116
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/191881

From-SVN: r274998
This commit is contained in:
Ian Lance Taylor 2019-08-28 18:27:30 +00:00
parent 464969eb9b
commit fc4f90f0c8
10 changed files with 739 additions and 223 deletions

View File

@ -1,4 +1,4 @@
a6ddd0e1208a7d229c10be630c1110b3914038f5
189ff44b2c26f29f41f0eb159e0d8f3fa508ecae
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -594,67 +594,110 @@ Expression::backend_numeric_constant_expression(Translate_context* context,
return ret;
}
// Return an expression which evaluates to true if VAL, of arbitrary integer
// type, is negative or is more than the maximum value of the Go type "int".
// Insert bounds checks for an index expression. Check that that VAL
// >= 0 and that it fits in an int. Then check that VAL OP BOUND is
// true. If any condition is false, call one of the CODE runtime
// functions, which will panic.
Expression*
Expression::check_bounds(Expression* val, Location loc)
void
Expression::check_bounds(Expression* val, Operator op, Expression* bound,
Runtime::Function code,
Runtime::Function code_u,
Runtime::Function code_extend,
Runtime::Function code_extend_u,
Statement_inserter* inserter,
Location loc)
{
go_assert(val->is_variable() || val->is_constant());
go_assert(bound->is_variable() || bound->is_constant());
Type* int_type = Type::lookup_integer_type("int");
int int_type_size = int_type->integer_type()->bits();
Type* val_type = val->type();
Type* bound_type = Type::lookup_integer_type("int");
int val_type_size;
bool val_is_unsigned = false;
if (val_type->integer_type() != NULL)
if (val_type->integer_type() == NULL)
{
val_type_size = val_type->integer_type()->bits();
val_is_unsigned = val_type->integer_type()->is_unsigned();
go_assert(saw_errors());
return;
}
else
{
if (!val_type->is_numeric_type()
|| !Type::are_convertible(bound_type, val_type, NULL))
{
go_assert(saw_errors());
return Expression::make_boolean(true, loc);
}
int val_type_size = val_type->integer_type()->bits();
bool val_is_unsigned = val_type->integer_type()->is_unsigned();
if (val_type->complex_type() != NULL)
val_type_size = val_type->complex_type()->bits();
else
val_type_size = val_type->float_type()->bits();
}
Expression* negative_index = Expression::make_boolean(false, loc);
Expression* index_overflows = Expression::make_boolean(false, loc);
// Check that VAL >= 0.
Expression* check = NULL;
if (!val_is_unsigned)
{
Expression* zero = Expression::make_integer_ul(0, val_type, loc);
negative_index = Expression::make_binary(OPERATOR_LT, val, zero, loc);
check = Expression::make_binary(OPERATOR_GE, val->copy(), zero, loc);
}
int bound_type_size = bound_type->integer_type()->bits();
if (val_type_size > bound_type_size
|| (val_type_size == bound_type_size
// If VAL's type is larger than int, check that VAL fits in an int.
if (val_type_size > int_type_size
|| (val_type_size == int_type_size
&& val_is_unsigned))
{
mpz_t one;
mpz_init_set_ui(one, 1UL);
// maxval = 2^(bound_type_size - 1) - 1
// maxval = 2^(int_type_size - 1) - 1
mpz_t maxval;
mpz_init(maxval);
mpz_mul_2exp(maxval, one, bound_type_size - 1);
mpz_mul_2exp(maxval, one, int_type_size - 1);
mpz_sub_ui(maxval, maxval, 1);
Expression* max = Expression::make_integer_z(&maxval, val_type, loc);
mpz_clear(one);
mpz_clear(maxval);
index_overflows = Expression::make_binary(OPERATOR_GT, val, max, loc);
Expression* cmp = Expression::make_binary(OPERATOR_LE, val->copy(),
max, loc);
if (check == NULL)
check = cmp;
else
check = Expression::make_binary(OPERATOR_ANDAND, check, cmp, loc);
}
return Expression::make_binary(OPERATOR_OROR, negative_index, index_overflows,
loc);
// For the final check we can assume that VAL fits in an int.
Expression* ival;
if (val_type == int_type)
ival = val->copy();
else
ival = Expression::make_cast(int_type, val->copy(), loc);
// BOUND is assumed to fit in an int. Either it comes from len or
// cap, or it was checked by an earlier call.
Expression* ibound;
if (bound->type() == int_type)
ibound = bound->copy();
else
ibound = Expression::make_cast(int_type, bound->copy(), loc);
Expression* cmp = Expression::make_binary(op, ival, ibound, loc);
if (check == NULL)
check = cmp;
else
check = Expression::make_binary(OPERATOR_ANDAND, check, cmp, loc);
Runtime::Function c;
if (val_type_size > int_type_size)
{
if (val_is_unsigned)
c = code_extend_u;
else
c = code_extend;
}
else
{
if (val_is_unsigned)
c = code_u;
else
c = code;
}
Expression* ignore = Expression::make_boolean(true, loc);
Expression* crash = Runtime::make_call(c, loc, 2,
val->copy(), bound->copy());
Expression* cond = Expression::make_conditional(check, ignore, crash, loc);
inserter->insert(Statement::make_statement(cond, true));
}
void
@ -12666,7 +12709,8 @@ Array_index_expression::do_check_types(Gogo*)
unsigned long v;
if (this->start_->type()->integer_type() == NULL
&& !this->start_->type()->is_error()
&& (!this->start_->numeric_constant_value(&nc)
&& (!this->start_->type()->is_abstract()
|| !this->start_->numeric_constant_value(&nc)
|| nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT))
this->report_error(_("index must be integer"));
if (this->end_ != NULL
@ -12674,7 +12718,8 @@ Array_index_expression::do_check_types(Gogo*)
&& !this->end_->type()->is_error()
&& !this->end_->is_nil_expression()
&& !this->end_->is_error_expression()
&& (!this->end_->numeric_constant_value(&nc)
&& (!this->end_->type()->is_abstract()
|| !this->end_->numeric_constant_value(&nc)
|| nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT))
this->report_error(_("slice end must be integer"));
if (this->cap_ != NULL
@ -12682,7 +12727,8 @@ Array_index_expression::do_check_types(Gogo*)
&& !this->cap_->type()->is_error()
&& !this->cap_->is_nil_expression()
&& !this->cap_->is_error_expression()
&& (!this->cap_->numeric_constant_value(&nc)
&& (!this->cap_->type()->is_abstract()
|| !this->cap_->numeric_constant_value(&nc)
|| nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT))
this->report_error(_("slice capacity must be integer"));
@ -12799,13 +12845,21 @@ Array_index_expression::do_must_eval_subexpressions_in_order(
return true;
}
// Flatten array indexing by using temporary variables for slices and indexes.
// Flatten array indexing: add temporary variables and bounds checks.
Expression*
Array_index_expression::do_flatten(Gogo*, Named_object*,
Array_index_expression::do_flatten(Gogo* gogo, Named_object*,
Statement_inserter* inserter)
{
if (this->is_flattened_)
return this;
this->is_flattened_ = true;
Location loc = this->location();
if (this->is_error_expression())
return Expression::make_error(loc);
Expression* array = this->array_;
Expression* start = this->start_;
Expression* end = this->end_;
@ -12823,34 +12877,157 @@ Array_index_expression::do_flatten(Gogo*, Named_object*,
return Expression::make_error(loc);
}
Array_type* array_type = this->array_->type()->array_type();
if (array_type == NULL)
{
go_assert(saw_errors());
return Expression::make_error(loc);
}
Temporary_statement* temp;
if (array->type()->is_slice_type() && !array->is_variable())
if (array_type->is_slice_type() && !array->is_variable())
{
temp = Statement::make_temporary(NULL, array, loc);
inserter->insert(temp);
this->array_ = Expression::make_temporary_reference(temp, loc);
array = this->array_;
}
if (!start->is_variable())
if (!start->is_variable() && !start->is_constant())
{
temp = Statement::make_temporary(NULL, start, loc);
inserter->insert(temp);
this->start_ = Expression::make_temporary_reference(temp, loc);
start = this->start_;
}
if (end != NULL
&& !end->is_nil_expression()
&& !end->is_variable())
&& !end->is_variable()
&& !end->is_constant())
{
temp = Statement::make_temporary(NULL, end, loc);
inserter->insert(temp);
this->end_ = Expression::make_temporary_reference(temp, loc);
end = this->end_;
}
if (cap != NULL && !cap->is_variable())
if (cap != NULL && !cap->is_variable() && !cap->is_constant())
{
temp = Statement::make_temporary(NULL, cap, loc);
inserter->insert(temp);
this->cap_ = Expression::make_temporary_reference(temp, loc);
cap = this->cap_;
}
if (!this->needs_bounds_check_)
return this;
Expression* len;
if (!array_type->is_slice_type())
{
len = array_type->get_length(gogo, this->array_);
go_assert(len->is_constant());
}
else
{
len = array_type->get_length(gogo, this->array_->copy());
temp = Statement::make_temporary(NULL, len, loc);
inserter->insert(temp);
len = Expression::make_temporary_reference(temp, loc);
}
Expression* scap = NULL;
if (array_type->is_slice_type())
{
scap = array_type->get_capacity(gogo, this->array_->copy());
temp = Statement::make_temporary(NULL, scap, loc);
inserter->insert(temp);
scap = Expression::make_temporary_reference(temp, loc);
}
// The order of bounds checks here matches the order used by the gc
// compiler, as tested by issue30116[u].go.
if (cap != NULL)
{
if (array_type->is_slice_type())
Expression::check_bounds(cap, OPERATOR_LE, scap,
Runtime::PANIC_SLICE3_ACAP,
Runtime::PANIC_SLICE3_ACAP_U,
Runtime::PANIC_EXTEND_SLICE3_ACAP,
Runtime::PANIC_EXTEND_SLICE3_ACAP_U,
inserter, loc);
else
Expression::check_bounds(cap, OPERATOR_LE, len,
Runtime::PANIC_SLICE3_ALEN,
Runtime::PANIC_SLICE3_ALEN_U,
Runtime::PANIC_EXTEND_SLICE3_ALEN,
Runtime::PANIC_EXTEND_SLICE3_ALEN_U,
inserter, loc);
Expression* start_bound = cap;
if (end != NULL && !end->is_nil_expression())
{
Expression::check_bounds(end, OPERATOR_LE, cap,
Runtime::PANIC_SLICE3_B,
Runtime::PANIC_SLICE3_B_U,
Runtime::PANIC_EXTEND_SLICE3_B,
Runtime::PANIC_EXTEND_SLICE3_B_U,
inserter, loc);
start_bound = end;
}
Expression::check_bounds(start, OPERATOR_LE, start_bound,
Runtime::PANIC_SLICE3_C,
Runtime::PANIC_SLICE3_C_U,
Runtime::PANIC_EXTEND_SLICE3_C,
Runtime::PANIC_EXTEND_SLICE3_C_U,
inserter, loc);
}
else if (end != NULL && !end->is_nil_expression())
{
if (array_type->is_slice_type())
Expression::check_bounds(end, OPERATOR_LE, scap,
Runtime::PANIC_SLICE_ACAP,
Runtime::PANIC_SLICE_ACAP_U,
Runtime::PANIC_EXTEND_SLICE_ACAP,
Runtime::PANIC_EXTEND_SLICE_ACAP_U,
inserter, loc);
else
Expression::check_bounds(end, OPERATOR_LE, len,
Runtime::PANIC_SLICE_ALEN,
Runtime::PANIC_SLICE_ALEN_U,
Runtime::PANIC_EXTEND_SLICE_ALEN,
Runtime::PANIC_EXTEND_SLICE_ALEN_U,
inserter, loc);
Expression::check_bounds(start, OPERATOR_LE, end,
Runtime::PANIC_SLICE_B,
Runtime::PANIC_SLICE_B_U,
Runtime::PANIC_EXTEND_SLICE_B,
Runtime::PANIC_EXTEND_SLICE_B_U,
inserter, loc);
}
else if (end != NULL)
{
Expression* start_bound;
if (array_type->is_slice_type())
start_bound = scap;
else
start_bound = len;
Expression::check_bounds(start, OPERATOR_LE, start_bound,
Runtime::PANIC_SLICE_B,
Runtime::PANIC_SLICE_B_U,
Runtime::PANIC_EXTEND_SLICE_B,
Runtime::PANIC_EXTEND_SLICE_B_U,
inserter, loc);
}
else
Expression::check_bounds(start, OPERATOR_LT, len,
Runtime::PANIC_INDEX,
Runtime::PANIC_INDEX_U,
Runtime::PANIC_EXTEND_INDEX,
Runtime::PANIC_EXTEND_INDEX_U,
inserter, loc);
return this;
}
@ -12899,10 +13076,8 @@ Array_index_expression::do_get_backend(Translate_context* context)
Type* int_type = Type::lookup_integer_type("int");
Btype* int_btype = int_type->get_backend(gogo);
// We need to convert the length and capacity to the Go "int" type here
// because the length of a fixed-length array could be of type "uintptr"
// and gimple disallows binary operations between "uintptr" and other
// integer types. FIXME.
// Convert the length and capacity to "int". FIXME: Do we need to
// do this?
Bexpression* length = NULL;
if (this->end_ == NULL || this->end_->is_nil_expression())
{
@ -12939,53 +13114,18 @@ Array_index_expression::do_get_backend(Translate_context* context)
Bexpression* start = this->start_->get_backend(context);
start = gogo->backend()->convert_expression(int_btype, start, loc);
Bexpression* crash = NULL;
Bexpression* bad_index = NULL;
if (this->needs_bounds_check_)
{
int code = (array_type->length() != NULL
? (this->end_ == NULL
? RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS
: RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS)
: (this->end_ == NULL
? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS
: RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS));
crash = gogo->runtime_error(code, loc)->get_backend(context);
bad_index = Expression::check_bounds(this->start_, loc)->get_backend(context);
Bexpression* start_too_large =
gogo->backend()->binary_expression((this->end_ == NULL
? OPERATOR_GE
: OPERATOR_GT),
start,
(this->end_ == NULL
? length
: capacity),
loc);
bad_index = gogo->backend()->binary_expression(OPERATOR_OROR,
start_too_large,
bad_index, loc);
}
Bfunction* bfn = context->function()->func_value()->get_decl();
if (this->end_ == NULL)
{
// Simple array indexing. This has to return an l-value, so
// wrap the index check into START.
if (this->needs_bounds_check_)
start =
gogo->backend()->conditional_expression(bfn, int_btype, bad_index,
crash, start, loc);
// Simple array indexing.
Bexpression* ret;
if (array_type->length() != NULL)
if (!array_type->is_slice_type())
{
Bexpression* array = this->array_->get_backend(context);
ret = gogo->backend()->array_index_expression(array, start, loc);
}
else
{
// Slice.
Expression* valptr =
array_type->get_value_pointer(gogo, this->array_,
this->is_lvalue_);
@ -12999,31 +13139,7 @@ Array_index_expression::do_get_backend(Translate_context* context)
return ret;
}
// Array slice.
if (this->cap_ != NULL)
{
cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc);
if (this->needs_bounds_check_)
{
Bexpression* bounds_bcheck =
Expression::check_bounds(this->cap_, loc)->get_backend(context);
bad_index =
gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
bad_index, loc);
Bexpression* cap_too_small =
gogo->backend()->binary_expression(OPERATOR_LT, cap_arg, start, loc);
Bexpression* cap_too_large =
gogo->backend()->binary_expression(OPERATOR_GT, cap_arg, capacity, loc);
Bexpression* bad_cap =
gogo->backend()->binary_expression(OPERATOR_OROR, cap_too_small,
cap_too_large, loc);
bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_cap,
bad_index, loc);
}
}
// Slice expression.
Bexpression* end;
if (this->end_->is_nil_expression())
@ -13032,24 +13148,6 @@ Array_index_expression::do_get_backend(Translate_context* context)
{
end = this->end_->get_backend(context);
end = gogo->backend()->convert_expression(int_btype, end, loc);
if (this->needs_bounds_check_)
{
Bexpression* bounds_bcheck =
Expression::check_bounds(this->end_, loc)->get_backend(context);
bad_index =
gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
bad_index, loc);
Bexpression* end_too_small =
gogo->backend()->binary_expression(OPERATOR_LT, end, start, loc);
Bexpression* end_too_large =
gogo->backend()->binary_expression(OPERATOR_GT, end, cap_arg, loc);
Bexpression* bad_end =
gogo->backend()->binary_expression(OPERATOR_OROR, end_too_small,
end_too_large, loc);
bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_end,
bad_index, loc);
}
}
Bexpression* result_length =
@ -13081,12 +13179,7 @@ Array_index_expression::do_get_backend(Translate_context* context)
init.push_back(result_length);
init.push_back(result_capacity);
Bexpression* ret =
gogo->backend()->constructor_expression(struct_btype, init, loc);
if (this->needs_bounds_check_)
ret = gogo->backend()->conditional_expression(bfn, struct_btype, bad_index,
crash, ret, loc);
return ret;
return gogo->backend()->constructor_expression(struct_btype, init, loc);
}
// Export an array index expression.
@ -13164,7 +13257,15 @@ Expression*
String_index_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
if (this->is_flattened_)
return this;
this->is_flattened_ = true;
Location loc = this->location();
if (this->is_error_expression())
return Expression::make_error(loc);
Expression* string = this->string_;
Expression* start = this->start_;
Expression* end = this->end_;
@ -13180,27 +13281,69 @@ String_index_expression::do_flatten(Gogo*, Named_object*,
}
Temporary_statement* temp;
if (!this->string_->is_variable())
if (!string->is_variable())
{
temp = Statement::make_temporary(NULL, this->string_, loc);
temp = Statement::make_temporary(NULL, string, loc);
inserter->insert(temp);
this->string_ = Expression::make_temporary_reference(temp, loc);
string = this->string_;
}
if (!this->start_->is_variable())
if (!start->is_variable())
{
temp = Statement::make_temporary(NULL, this->start_, loc);
temp = Statement::make_temporary(NULL, start, loc);
inserter->insert(temp);
this->start_ = Expression::make_temporary_reference(temp, loc);
start = this->start_;
}
if (this->end_ != NULL
&& !this->end_->is_nil_expression()
&& !this->end_->is_variable())
if (end != NULL
&& !end->is_nil_expression()
&& !end->is_variable())
{
temp = Statement::make_temporary(NULL, this->end_, loc);
temp = Statement::make_temporary(NULL, end, loc);
inserter->insert(temp);
this->end_ = Expression::make_temporary_reference(temp, loc);
end = this->end_;
}
Expression* len = Expression::make_string_info(string->copy(),
STRING_INFO_LENGTH, loc);
temp = Statement::make_temporary(NULL, len, loc);
inserter->insert(temp);
len = Expression::make_temporary_reference(temp, loc);
// The order of bounds checks here matches the order used by the gc
// compiler, as tested by issue30116[u].go.
if (end != NULL && !end->is_nil_expression())
{
Expression::check_bounds(end, OPERATOR_LE, len,
Runtime::PANIC_SLICE_ALEN,
Runtime::PANIC_SLICE_ALEN_U,
Runtime::PANIC_EXTEND_SLICE_ALEN,
Runtime::PANIC_EXTEND_SLICE_ALEN_U,
inserter, loc);
Expression::check_bounds(start, OPERATOR_LE, end,
Runtime::PANIC_SLICE_B,
Runtime::PANIC_SLICE_B_U,
Runtime::PANIC_EXTEND_SLICE_B,
Runtime::PANIC_EXTEND_SLICE_B_U,
inserter, loc);
}
else if (end != NULL)
Expression::check_bounds(start, OPERATOR_LE, len,
Runtime::PANIC_SLICE_B,
Runtime::PANIC_SLICE_B_U,
Runtime::PANIC_EXTEND_SLICE_B,
Runtime::PANIC_EXTEND_SLICE_B_U,
inserter, loc);
else
Expression::check_bounds(start, OPERATOR_LT, len,
Runtime::PANIC_INDEX,
Runtime::PANIC_INDEX_U,
Runtime::PANIC_EXTEND_INDEX,
Runtime::PANIC_EXTEND_INDEX_U,
inserter, loc);
return this;
}
@ -13245,7 +13388,8 @@ String_index_expression::do_check_types(Gogo*)
unsigned long v;
if (this->start_->type()->integer_type() == NULL
&& !this->start_->type()->is_error()
&& (!this->start_->numeric_constant_value(&nc)
&& (!this->start_->type()->is_abstract()
|| !this->start_->numeric_constant_value(&nc)
|| nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT))
this->report_error(_("index must be integer"));
if (this->end_ != NULL
@ -13253,7 +13397,8 @@ String_index_expression::do_check_types(Gogo*)
&& !this->end_->type()->is_error()
&& !this->end_->is_nil_expression()
&& !this->end_->is_error_expression()
&& (!this->end_->numeric_constant_value(&nc)
&& (!this->end_->type()->is_abstract()
|| !this->end_->numeric_constant_value(&nc)
|| nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT))
this->report_error(_("slice end must be integer"));
@ -13303,14 +13448,7 @@ Bexpression*
String_index_expression::do_get_backend(Translate_context* context)
{
Location loc = this->location();
Expression* bad_index = Expression::check_bounds(this->start_, loc);
int code = (this->end_ == NULL
? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS
: RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS);
Gogo* gogo = context->gogo();
Bexpression* crash = gogo->runtime_error(code, loc)->get_backend(context);
Type* int_type = Type::lookup_integer_type("int");
@ -13342,21 +13480,9 @@ String_index_expression::do_get_backend(Translate_context* context)
if (this->end_ == NULL)
{
Expression* start_too_large =
Expression::make_binary(OPERATOR_GE, start, length, loc);
bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large,
bad_index, loc);
ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc);
Btype* ubtype = Type::lookup_integer_type("uint8")->get_backend(gogo);
Bexpression* index =
gogo->backend()->indirect_expression(ubtype, ptr, true, loc);
Btype* byte_btype = bytes->type()->points_to()->get_backend(gogo);
Bexpression* index_error = bad_index->get_backend(context);
return gogo->backend()->conditional_expression(bfn, byte_btype,
index_error, crash,
index, loc);
return gogo->backend()->indirect_expression(ubtype, ptr, true, loc);
}
Expression* end = NULL;
@ -13365,20 +13491,8 @@ String_index_expression::do_get_backend(Translate_context* context)
else
{
go_assert(this->end_->is_variable());
Expression* bounds_check = Expression::check_bounds(this->end_, loc);
bad_index =
Expression::make_binary(OPERATOR_OROR, bounds_check, bad_index, loc);
end = Expression::make_cast(int_type, this->end_, loc);
Expression* end_too_large =
Expression::make_binary(OPERATOR_GT, end, length, loc);
bad_index = Expression::make_binary(OPERATOR_OROR, end_too_large,
bad_index, loc);
}
Expression* start_too_large =
Expression::make_binary(OPERATOR_GT, start->copy(), end->copy(), loc);
bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large,
bad_index, loc);
end = end->copy();
Bexpression* bend = end->get_backend(context);
@ -13405,12 +13519,7 @@ String_index_expression::do_get_backend(Translate_context* context)
std::vector<Bexpression*> init;
init.push_back(ptr);
init.push_back(new_length);
Bexpression* bstrslice =
gogo->backend()->constructor_expression(str_btype, init, loc);
Bexpression* index_error = bad_index->get_backend(context);
return gogo->backend()->conditional_expression(bfn, str_btype, index_error,
crash, bstrslice, loc);
return gogo->backend()->constructor_expression(str_btype, init, loc);
}
// Export a string index expression.

View File

@ -1059,10 +1059,11 @@ class Expression
static Expression*
import_expression(Import_expression*, Location);
// Return an expression which checks that VAL, of arbitrary integer type,
// is non-negative and is not more than the maximum integer value.
static Expression*
check_bounds(Expression* val, Location);
// Insert bounds checks for an index expression.
static void
check_bounds(Expression* val, Operator, Expression* bound, Runtime::Function,
Runtime::Function, Runtime::Function, Runtime::Function,
Statement_inserter*, Location);
// Return an expression for constructing a direct interface type from a
// pointer.
@ -2998,7 +2999,7 @@ class Array_index_expression : public Expression
Expression* end, Expression* cap, Location location)
: Expression(EXPRESSION_ARRAY_INDEX, location),
array_(array), start_(start), end_(end), cap_(cap), type_(NULL),
is_lvalue_(false), needs_bounds_check_(true)
is_lvalue_(false), needs_bounds_check_(true), is_flattened_(false)
{ }
// Return the array.
@ -3121,6 +3122,8 @@ class Array_index_expression : public Expression
bool is_lvalue_;
// Whether bounds check is needed.
bool needs_bounds_check_;
// Whether this has already been flattened.
bool is_flattened_;
};
// A string index. This is used for both indexing and slicing.
@ -3131,7 +3134,7 @@ class String_index_expression : public Expression
String_index_expression(Expression* string, Expression* start,
Expression* end, Location location)
: Expression(EXPRESSION_STRING_INDEX, location),
string_(string), start_(start), end_(end)
string_(string), start_(start), end_(end), is_flattened_(false)
{ }
// Return the string being indexed.
@ -3203,6 +3206,8 @@ class String_index_expression : public Expression
// The end index of a slice. This may be NULL for a single index,
// or it may be a nil expression for the length of the string.
Expression* end_;
// Whether this has already been flattened.
bool is_flattened_;
};
// An index into a map.

View File

@ -6300,6 +6300,7 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no)
}
if (this->asm_name_ == "runtime.gopanic"
|| this->asm_name_.compare(0, 15, "runtime.goPanic") == 0
|| this->asm_name_ == "__go_runtime_error"
|| this->asm_name_ == "runtime.panicdottype"
|| this->asm_name_ == "runtime.block")

View File

@ -30,6 +30,8 @@ enum Runtime_function_type
RFT_BOOLPTR,
// Go type int, C type intgo.
RFT_INT,
// Go type uint, C type uintgo.
RFT_UINT,
// Go type uint8, C type uint8_t.
RFT_UINT8,
// Go type uint16, C type uint16_t.
@ -113,6 +115,10 @@ runtime_function_type(Runtime_function_type bft)
t = Type::lookup_integer_type("int");
break;
case RFT_UINT:
t = Type::lookup_integer_type("uint");
break;
case RFT_UINT8:
t = Type::lookup_integer_type("uint8");
break;
@ -262,6 +268,7 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
case RFT_BOOL:
case RFT_BOOLPTR:
case RFT_INT:
case RFT_UINT:
case RFT_UINT8:
case RFT_UINT16:
case RFT_INT32:

View File

@ -499,6 +499,75 @@ DEF_GO_RUNTIME(ATOMIC_OR_FETCH_1, "__atomic_or_fetch_1",
P3(POINTER, UINT8, INT32),
R1(UINT8))
// Panics reporting an index or slice out of bounds error.
DEF_GO_RUNTIME(PANIC_INDEX, "runtime.goPanicIndex",
P2(INT, INT), R0())
DEF_GO_RUNTIME(PANIC_INDEX_U, "runtime.goPanicIndexU",
P2(UINT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE_ALEN, "runtime.goPanicSliceAlen",
P2(INT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE_ALEN_U, "runtime.goPanicSliceAlenU",
P2(UINT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE_ACAP, "runtime.goPanicSliceAcap",
P2(INT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE_ACAP_U, "runtime.goPanicSliceAcapU",
P2(UINT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE_B, "runtime.goPanicSliceB",
P2(INT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE_B_U, "runtime.goPanicSliceBU",
P2(UINT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE3_ALEN, "runtime.goPanicSlice3Alen",
P2(INT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE3_ALEN_U, "runtime.goPanicSlice3AlenU",
P2(UINT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE3_ACAP, "runtime.goPanicSlice3Acap",
P2(INT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE3_ACAP_U, "runtime.goPanicSlice3AcapU",
P2(UINT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE3_B, "runtime.goPanicSlice3B",
P2(INT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE3_B_U, "runtime.goPanicSlice3BU",
P2(UINT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE3_C, "runtime.goPanicSlice3C",
P2(INT, INT), R0())
DEF_GO_RUNTIME(PANIC_SLICE3_C_U, "runtime.goPanicSlice3CU",
P2(UINT, INT), R0())
// Panics reporting an index or slice out of bounds error with a
// 64-bit index type. These are only used by 32-bit targets.
DEF_GO_RUNTIME(PANIC_EXTEND_INDEX, "runtime.goPanicExtendIndex",
P2(INT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_INDEX_U, "runtime.goPanicExtendIndexU",
P2(UINT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_ALEN, "runtime.goPanicExtendSliceAlen",
P2(INT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_ALEN_U, "runtime.goPanicExtendSliceAlenU",
P2(UINT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_ACAP, "runtime.goPanicExtendSliceAcap",
P2(INT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_ACAP_U, "runtime.goPanicExtendSliceAcapU",
P2(UINT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_B, "runtime.goPanicExtendSliceB",
P2(INT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_B_U, "runtime.goPanicExtendSliceBU",
P2(UINT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_ALEN, "runtime.goPanicExtendSlice3Alen",
P2(INT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_ALEN_U, "runtime.goPanicExtendSlice3AlenU",
P2(UINT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_ACAP, "runtime.goPanicExtendSlice3Acap",
P2(INT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_ACAP_U, "runtime.goPanicExtendSlice3AcapU",
P2(UINT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_B, "runtime.goPanicExtendSlice3B",
P2(INT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_B_U, "runtime.goPanicExtendSlice3BU",
P2(UINT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_C, "runtime.goPanicExtendSlice3C",
P2(INT64, INT), R0())
DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_C_U, "runtime.goPanicExtendSlice3CU",
P2(UINT64, INT), R0())
// Remove helper macros.
#undef ABFT6
#undef ABFT2

View File

@ -79,6 +79,21 @@ func unquote(s string) string {
return string(r[:j])
}
//go:nosplit
// itoa converts val to a decimal representation. The result is
// written somewhere within buf and the location of the result is returned.
// buf must be at least 20 bytes.
func itoa(buf []byte, val uint64) []byte {
i := len(buf) - 1
for val >= 10 {
buf[i] = byte(val%10 + '0')
i--
val /= 10
}
buf[i] = byte(val + '0')
return buf[i:]
}
// An errorString represents a runtime error described by a single string.
type errorString string
@ -114,6 +129,99 @@ func (e plainError) Error() string {
return string(e)
}
// An boundsError represents a an indexing or slicing operation gone wrong.
type boundsError struct {
x int64
y int
// Values in an index or slice expression can be signed or unsigned.
// That means we'd need 65 bits to encode all possible indexes, from -2^63 to 2^64-1.
// Instead, we keep track of whether x should be interpreted as signed or unsigned.
// y is known to be nonnegative and to fit in an int.
signed bool
code boundsErrorCode
}
type boundsErrorCode uint8
const (
boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed
boundsSliceAlen // s[?:x], 0 <= x <= len(s) failed
boundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed
boundsSliceB // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen)
boundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed
boundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed
boundsSlice3B // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen)
boundsSlice3C // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen)
// Note: in the above, len(s) and cap(s) are stored in y
)
// boundsErrorFmts provide error text for various out-of-bounds panics.
// Note: if you change these strings, you should adjust the size of the buffer
// in boundsError.Error below as well.
var boundsErrorFmts = [...]string{
boundsIndex: "index out of range [%x] with length %y",
boundsSliceAlen: "slice bounds out of range [:%x] with length %y",
boundsSliceAcap: "slice bounds out of range [:%x] with capacity %y",
boundsSliceB: "slice bounds out of range [%x:%y]",
boundsSlice3Alen: "slice bounds out of range [::%x] with length %y",
boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y",
boundsSlice3B: "slice bounds out of range [:%x:%y]",
boundsSlice3C: "slice bounds out of range [%x:%y:]",
}
// boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y.
var boundsNegErrorFmts = [...]string{
boundsIndex: "index out of range [%x]",
boundsSliceAlen: "slice bounds out of range [:%x]",
boundsSliceAcap: "slice bounds out of range [:%x]",
boundsSliceB: "slice bounds out of range [%x:]",
boundsSlice3Alen: "slice bounds out of range [::%x]",
boundsSlice3Acap: "slice bounds out of range [::%x]",
boundsSlice3B: "slice bounds out of range [:%x:]",
boundsSlice3C: "slice bounds out of range [%x::]",
}
func (e boundsError) RuntimeError() {}
func appendIntStr(b []byte, v int64, signed bool) []byte {
if signed && v < 0 {
b = append(b, '-')
v = -v
}
var buf [20]byte
b = append(b, itoa(buf[:], uint64(v))...)
return b
}
func (e boundsError) Error() string {
fmt := boundsErrorFmts[e.code]
if e.signed && e.x < 0 {
fmt = boundsNegErrorFmts[e.code]
}
// max message length is 99: "runtime error: slice bounds out of range [::%x] with capacity %y"
// x can be at most 20 characters. y can be at most 19.
b := make([]byte, 0, 100)
b = append(b, "runtime error: "...)
for i := 0; i < len(fmt); i++ {
c := fmt[i]
if c != '%' {
b = append(b, c)
continue
}
i++
switch fmt[i] {
case 'x':
b = appendIntStr(b, e.x, e.signed)
case 'y':
b = appendIntStr(b, int64(e.y), true)
}
}
return string(b)
}
type stringer interface {
String() string
}

View File

@ -23,81 +23,189 @@ import (
//go:linkname makefuncreturning runtime.makefuncreturning
//go:linkname gorecover runtime.gorecover
//go:linkname deferredrecover runtime.deferredrecover
//go:linkname goPanicIndex runtime.goPanicIndex
//go:linkname goPanicIndexU runtime.goPanicIndexU
//go:linkname goPanicSliceAlen runtime.goPanicSliceAlen
//go:linkname goPanicSliceAlenU runtime.goPanicSliceAlenU
//go:linkname goPanicSliceAcap runtime.goPanicSliceAcap
//go:linkname goPanicSliceAcapU runtime.goPanicSliceAcapU
//go:linkname goPanicSliceB runtime.goPanicSliceB
//go:linkname goPanicSliceBU runtime.goPanicSliceBU
//go:linkname goPanicSlice3Alen runtime.goPanicSlice3Alen
//go:linkname goPanicSlice3AlenU runtime.goPanicSlice3AlenU
//go:linkname goPanicSlice3Acap runtime.goPanicSlice3Acap
//go:linkname goPanicSlice3AcapU runtime.goPanicSlice3AcapU
//go:linkname goPanicSlice3B runtime.goPanicSlice3B
//go:linkname goPanicSlice3BU runtime.goPanicSlice3BU
//go:linkname goPanicSlice3C runtime.goPanicSlice3C
//go:linkname goPanicSlice3CU runtime.goPanicSlice3CU
//go:linkname panicmem runtime.panicmem
// Temporary for C code to call:
//go:linkname throw runtime.throw
// Calling panic with one of the errors below will call errorString.Error
// which will call mallocgc to concatenate strings. That will fail if
// malloc is locked, causing a confusing error message. Throw a better
// error message instead.
func panicCheckMalloc(err error) {
// Check to make sure we can really generate a panic. If the panic
// was generated from the runtime, or from inside malloc, then convert
// to a throw of msg.
// pc should be the program counter of the compiler-generated code that
// triggered this panic.
func panicCheck1(pc uintptr, msg string) {
name, _, _, _ := funcfileline(pc-1, -1)
if hasPrefix(name, "runtime.") {
throw(msg)
}
// TODO: is this redundant? How could we be in malloc
// but not in the runtime? runtime/internal/*, maybe?
gp := getg()
if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
throw(string(err.(errorString)))
throw(msg)
}
}
var indexError = error(errorString("index out of range"))
// Same as above, but calling from the runtime is allowed.
//
// Using this function is necessary for any panic that may be
// generated by runtime.sigpanic, since those are always called by the
// runtime.
func panicCheck2(err string) {
// panic allocates, so to avoid recursive malloc, turn panics
// during malloc into throws.
gp := getg()
if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
throw(err)
}
}
// The panicindex, panicslice, and panicdivide functions are called by
// Many of the following panic entry-points turn into throws when they
// happen in various runtime contexts. These should never happen in
// the runtime, and if they do, they indicate a serious issue and
// should not be caught by user code.
//
// The panic{Index,Slice,divide,shift} functions are called by
// code generated by the compiler for out of bounds index expressions,
// out of bounds slice expressions, and division by zero. The
// panicdivide (again), panicoverflow, panicfloat, and panicmem
// out of bounds slice expressions, division by zero, and shift by negative.
// The panicdivide (again), panicoverflow, panicfloat, and panicmem
// functions are called by the signal handler when a signal occurs
// indicating the respective problem.
//
// Since panicindex and panicslice are never called directly, and
// Since panic{Index,Slice,shift} are never called directly, and
// since the runtime package should never have an out of bounds slice
// or array reference, if we see those functions called from the
// or array reference or negative shift, if we see those functions called from the
// runtime package we turn the panic into a throw. That will dump the
// entire runtime stack for easier debugging.
//
// The entry points called by the signal handler will be called from
// runtime.sigpanic, so we can't disallow calls from the runtime to
// these (they always look like they're called from the runtime).
// Hence, for these, we just check for clearly bad runtime conditions.
func panicindex() {
name, _, _, _ := funcfileline(getcallerpc()-1, -1)
if hasPrefix(name, "runtime.") {
throw(string(indexError.(errorString)))
}
panicCheckMalloc(indexError)
panic(indexError)
// failures in the comparisons for s[x], 0 <= x < y (y == len(s))
func goPanicIndex(x int, y int) {
panicCheck1(getcallerpc(), "index out of range")
panic(boundsError{x: int64(x), signed: true, y: y, code: boundsIndex})
}
func goPanicIndexU(x uint, y int) {
panicCheck1(getcallerpc(), "index out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsIndex})
}
var sliceError = error(errorString("slice bounds out of range"))
// failures in the comparisons for s[:x], 0 <= x <= y (y == len(s) or cap(s))
func goPanicSliceAlen(x int, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAlen})
}
func goPanicSliceAlenU(x uint, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAlen})
}
func goPanicSliceAcap(x int, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAcap})
}
func goPanicSliceAcapU(x uint, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAcap})
}
func panicslice() {
name, _, _, _ := funcfileline(getcallerpc()-1, -1)
if hasPrefix(name, "runtime.") {
throw(string(sliceError.(errorString)))
}
panicCheckMalloc(sliceError)
panic(sliceError)
// failures in the comparisons for s[x:y], 0 <= x <= y
func goPanicSliceB(x int, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceB})
}
func goPanicSliceBU(x uint, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceB})
}
// failures in the comparisons for s[::x], 0 <= x <= y (y == len(s) or cap(s))
func goPanicSlice3Alen(x int, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Alen})
}
func goPanicSlice3AlenU(x uint, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Alen})
}
func goPanicSlice3Acap(x int, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Acap})
}
func goPanicSlice3AcapU(x uint, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Acap})
}
// failures in the comparisons for s[:x:y], 0 <= x <= y
func goPanicSlice3B(x int, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3B})
}
func goPanicSlice3BU(x uint, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3B})
}
// failures in the comparisons for s[x:y:], 0 <= x <= y
func goPanicSlice3C(x int, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3C})
}
func goPanicSlice3CU(x uint, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3C})
}
var shiftError = error(errorString("negative shift amount"))
func panicshift() {
panicCheck1(getcallerpc(), "negative shift amount")
panic(shiftError)
}
var divideError = error(errorString("integer divide by zero"))
func panicdivide() {
panicCheckMalloc(divideError)
panicCheck2("integer divide by zero")
panic(divideError)
}
var overflowError = error(errorString("integer overflow"))
func panicoverflow() {
panicCheckMalloc(overflowError)
panicCheck2("integer overflow")
panic(overflowError)
}
var floatError = error(errorString("floating point error"))
func panicfloat() {
panicCheckMalloc(floatError)
panicCheck2("floating point error")
panic(floatError)
}
var memoryError = error(errorString("invalid memory address or nil pointer dereference"))
func panicmem() {
panicCheckMalloc(memoryError)
panicCheck2("invalid memory address or nil pointer dereference")
panic(memoryError)
}

108
libgo/go/runtime/panic32.go Normal file
View File

@ -0,0 +1,108 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build 386 amd64p32 arm mips mipsle m68k nios2 sh shbe
package runtime
import _ "unsafe" // for go:linkname
// For gccgo, use go:linkname to rename compiler-called functions to
// themselves, so that the compiler will export them.
//
//go:linkname goPanicExtendIndex runtime.goPanicExtendIndex
//go:linkname goPanicExtendIndexU runtime.goPanicExtendIndexU
//go:linkname goPanicExtendSliceAlen runtime.goPanicExtendSliceAlen
//go:linkname goPanicExtendSliceAlenU runtime.goPanicExtendSliceAlenU
//go:linkname goPanicExtendSliceAcap runtime.goPanicExtendSliceAcap
//go:linkname goPanicExtendSliceAcapU runtime.goPanicExtendSliceAcapU
//go:linkname goPanicExtendSliceB runtime.goPanicExtendSliceB
//go:linkname goPanicExtendSliceBU runtime.goPanicExtendSliceBU
//go:linkname goPanicExtendSlice3Alen runtime.goPanicExtendSlice3Alen
//go:linkname goPanicExtendSlice3AlenU runtime.goPanicExtendSlice3AlenU
//go:linkname goPanicExtendSlice3Acap runtime.goPanicExtendSlice3Acap
//go:linkname goPanicExtendSlice3AcapU runtime.goPanicExtendSlice3AcapU
//go:linkname goPanicExtendSlice3B runtime.goPanicExtendSlice3B
//go:linkname goPanicExtendSlice3BU runtime.goPanicExtendSlice3BU
//go:linkname goPanicExtendSlice3C runtime.goPanicExtendSlice3C
//go:linkname goPanicExtendSlice3CU runtime.goPanicExtendSlice3CU
// Additional index/slice error paths for 32-bit platforms.
// Used when the high word of a 64-bit index is not zero.
// failures in the comparisons for s[x], 0 <= x < y (y == len(s))
func goPanicExtendIndex(x int64, y int) {
panicCheck1(getcallerpc(), "index out of range")
panic(boundsError{x: x, signed: true, y: y, code: boundsIndex})
}
func goPanicExtendIndexU(x uint64, y int) {
panicCheck1(getcallerpc(), "index out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsIndex})
}
// failures in the comparisons for s[:x], 0 <= x <= y (y == len(s) or cap(s))
func goPanicExtendSliceAlen(x int64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: x, signed: true, y: y, code: boundsSliceAlen})
}
func goPanicExtendSliceAlenU(x uint64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAlen})
}
func goPanicExtendSliceAcap(x int64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: x, signed: true, y: y, code: boundsSliceAcap})
}
func goPanicExtendSliceAcapU(x uint64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAcap})
}
// failures in the comparisons for s[x:y], 0 <= x <= y
func goPanicExtendSliceB(x int64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: x, signed: true, y: y, code: boundsSliceB})
}
func goPanicExtendSliceBU(x uint64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceB})
}
// failures in the comparisons for s[::x], 0 <= x <= y (y == len(s) or cap(s))
func goPanicExtendSlice3Alen(x int64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: x, signed: true, y: y, code: boundsSlice3Alen})
}
func goPanicExtendSlice3AlenU(x uint64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Alen})
}
func goPanicExtendSlice3Acap(x int64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: x, signed: true, y: y, code: boundsSlice3Acap})
}
func goPanicExtendSlice3AcapU(x uint64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Acap})
}
// failures in the comparisons for s[:x:y], 0 <= x <= y
func goPanicExtendSlice3B(x int64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: x, signed: true, y: y, code: boundsSlice3B})
}
func goPanicExtendSlice3BU(x uint64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3B})
}
// failures in the comparisons for s[x:y:], 0 <= x <= y
func goPanicExtendSlice3C(x int64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: x, signed: true, y: y, code: boundsSlice3C})
}
func goPanicExtendSlice3CU(x uint64, y int) {
panicCheck1(getcallerpc(), "slice bounds out of range")
panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3C})
}

View File

@ -15,14 +15,15 @@ rm -f runtime.inc.tmp2 runtime.inc.tmp3
# types and should not be exported back to C
# semt is a Go translation of the C type sem_t; it fails to convert on
# some systems and need not be exported back to C.
# sigset conflicts with system type sigset on AIX, so we need to rename it
# sigset conflicts with system type sigset on AIX, so we need to rename it.
# boundsError has a field name that is a C keyword, and we don't need it.
grep -v "#define _" ${IN} | grep -v "#define [cm][01234] " | grep -v "#define empty " | grep -v "#define \\$" > runtime.inc.tmp2
for pattern in '_[GP][a-z]' _Max _Lock _Sig _Trace _MHeap _Num
do
grep "#define $pattern" ${IN} >> runtime.inc.tmp2
done
TYPES="_Complex_lock _Reader_lock semt"
TYPES="_Complex_lock _Reader_lock semt boundsError"
for TYPE in $TYPES
do
sed -e '/struct '${TYPE}' {/,/^}/s/^.*$//' runtime.inc.tmp2 > runtime.inc.tmp3;