compiler, runtime: check len/cap for append(s, make(T, l)...)
authorIan Lance Taylor <iant@golang.org>
Sat, 28 Nov 2020 14:48:54 +0000 (06:48 -0800)
committerIan Lance Taylor <iant@golang.org>
Mon, 30 Nov 2020 20:22:14 +0000 (12:22 -0800)
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

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/runtime.def
libgo/go/runtime/slice.go

index e8cf468d8fc467ca9aec7478b5648657659b8b33..eec3d0708e56ac17532ea71a6226e146e63f3050 100644 (file)
@@ -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.
index d1546300d0e283252bd7f3e63ce27f0292e11e16..23caf61db93d9737004f36432f0754ec39990c97 100644 (file)
@@ -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.
index b608766cdaf88236e81df5fc99a72eca239a5204..9a3c68091308fd499988f3a99a08f61e543442e6 100644 (file)
@@ -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())
 
index 97b26594dadac4e12c4d31a3eb0d7758d10b64f2..ddd588ed5b937b7d98ae037e4e6e3956ee7d6561 100644 (file)
@@ -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 {