compiler, runtime: check len/cap for append(s, make(T, l)...)
The overflow checks done in growslice always reported an error for the capacity argument, even if it was the length argument that overflowed. This change lets the code pass the current issue4085b.go test. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/273806
This commit is contained in:
parent
e848a83f46
commit
9ebad4b01c
4 changed files with 28 additions and 25 deletions
|
@ -1,4 +1,4 @@
|
|||
be1738f1fff0e817d921ed568791f9b0585a6982
|
||||
84506e0f6bf282765856cb5aeb17124222f73042
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -8893,8 +8893,8 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function,
|
|||
// We will optimize this to directly zeroing the tail,
|
||||
// instead of allocating a new slice then copy.
|
||||
|
||||
// Retrieve the length. Cannot reference s2 as we will remove
|
||||
// the makeslice call.
|
||||
// Retrieve the length and capacity. Cannot reference s2 as
|
||||
// we will remove the makeslice call.
|
||||
Expression* len_arg = makecall->args()->at(1);
|
||||
len_arg = Expression::make_cast(int_type, len_arg, loc);
|
||||
l2tmp = Statement::make_temporary(int_type, len_arg, loc);
|
||||
|
@ -8907,28 +8907,19 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function,
|
|||
inserter->insert(c2tmp);
|
||||
|
||||
// Check bad len/cap here.
|
||||
// if len2 < 0 { panicmakeslicelen(); }
|
||||
// checkmakeslice(type, len, cap)
|
||||
// (Note that if len and cap are constants, we won't see a
|
||||
// makeslice call here, as it will be rewritten to a stack
|
||||
// allocated array by Mark_address_taken::expression.)
|
||||
Expression* elem = Expression::make_type_descriptor(element_type,
|
||||
loc);
|
||||
len2 = Expression::make_temporary_reference(l2tmp, loc);
|
||||
Expression* zero = Expression::make_integer_ul(0, int_type, loc);
|
||||
Expression* cond = Expression::make_binary(OPERATOR_LT, len2,
|
||||
zero, loc);
|
||||
Expression* call = Runtime::make_call(Runtime::PANIC_MAKE_SLICE_LEN,
|
||||
loc, 0);
|
||||
cond = Expression::make_conditional(cond, call, zero->copy(), loc);
|
||||
gogo->lower_expression(function, inserter, &cond);
|
||||
gogo->flatten_expression(function, inserter, &cond);
|
||||
Statement* s = Statement::make_statement(cond, false);
|
||||
inserter->insert(s);
|
||||
|
||||
// if cap2 < 0 { panicmakeslicecap(); }
|
||||
Expression* cap2 = Expression::make_temporary_reference(c2tmp, loc);
|
||||
cond = Expression::make_binary(OPERATOR_LT, cap2,
|
||||
zero->copy(), loc);
|
||||
call = Runtime::make_call(Runtime::PANIC_MAKE_SLICE_CAP, loc, 0);
|
||||
cond = Expression::make_conditional(cond, call, zero->copy(), loc);
|
||||
gogo->lower_expression(function, inserter, &cond);
|
||||
gogo->flatten_expression(function, inserter, &cond);
|
||||
s = Statement::make_statement(cond, false);
|
||||
Expression* check = Runtime::make_call(Runtime::CHECK_MAKE_SLICE,
|
||||
loc, 3, elem, len2, cap2);
|
||||
gogo->lower_expression(function, inserter, &check);
|
||||
gogo->flatten_expression(function, inserter, &check);
|
||||
Statement* s = Statement::make_statement(check, false);
|
||||
inserter->insert(s);
|
||||
|
||||
// Remove the original makeslice call.
|
||||
|
|
|
@ -265,6 +265,11 @@ DEF_GO_RUNTIME(GROWSLICE, "runtime.growslice",
|
|||
P5(TYPE, POINTER, INT, INT, INT), R1(SLICE))
|
||||
|
||||
|
||||
// Check the length and cap passed to make, without making a slice.
|
||||
// This is used for apend(s, make([]T, len)...).
|
||||
DEF_GO_RUNTIME(CHECK_MAKE_SLICE, "runtime.checkMakeSlice", P3(TYPE, INT, INT),
|
||||
R1(UINTPTR))
|
||||
|
||||
// Register roots (global variables) for the garbage collector.
|
||||
DEF_GO_RUNTIME(REGISTER_GC_ROOTS, "runtime.registerGCRoots", P1(POINTER), R0())
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
//go:linkname panicmakeslicelen
|
||||
//go:linkname panicmakeslicecap
|
||||
//go:linkname makeslice
|
||||
//go:linkname checkMakeSlice
|
||||
//go:linkname makeslice64
|
||||
//go:linkname growslice
|
||||
//go:linkname slicecopy
|
||||
|
@ -91,6 +92,13 @@ func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsaf
|
|||
}
|
||||
|
||||
func makeslice(et *_type, len, cap int) unsafe.Pointer {
|
||||
mem := checkMakeSlice(et, len, cap)
|
||||
return mallocgc(mem, et, true)
|
||||
}
|
||||
|
||||
// checkMakeSlice is called for append(s, make([]T, len, cap)...) to check
|
||||
// the values of len and cap.
|
||||
func checkMakeSlice(et *_type, len, cap int) uintptr {
|
||||
mem, overflow := math.MulUintptr(et.size, uintptr(cap))
|
||||
if overflow || mem > maxAlloc || len < 0 || len > cap {
|
||||
// NOTE: Produce a 'len out of range' error instead of a
|
||||
|
@ -104,8 +112,7 @@ func makeslice(et *_type, len, cap int) unsafe.Pointer {
|
|||
}
|
||||
panicmakeslicecap()
|
||||
}
|
||||
|
||||
return mallocgc(mem, et, true)
|
||||
return mem
|
||||
}
|
||||
|
||||
func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
|
||||
|
|
Loading…
Add table
Reference in a new issue