This patch to the Go compiler checks arguments to make for overflow if they have types larger than uintptr. In an attempt to be efficient on 32-bit systems, gccgo will continue to pass uintptr arguments in the normal case. If make is called with a value whose type is larger than uintptr (e.g., uint64 on a 32-bit system) then gccgo will call a different function which takes uint64 values and checks them for overflow. Without this patch we would silently accept invalid values. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
diff -r df952f89b74e go/expressions.cc --- a/go/expressions.cc Tue Feb 07 21:29:07 2012 -0800 +++ b/go/expressions.cc Tue Feb 07 22:13:53 2012 -0800 @@ -7744,6 +7744,10 @@ return Expression::make_error(this->location()); } + bool have_big_args = false; + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + int uintptr_bits = uintptr_type->integer_type()->bits(); + ++parg; Expression* len_arg; if (parg == args->end()) @@ -7767,6 +7771,9 @@ this->report_error(_("bad size for make")); return Expression::make_error(this->location()); } + if (len_arg->type()->integer_type() != NULL + && len_arg->type()->integer_type()->bits() > uintptr_bits) + have_big_args = true; ++parg; } @@ -7779,6 +7786,9 @@ this->report_error(_("bad capacity when making slice")); return Expression::make_error(this->location()); } + if (cap_arg->type()->integer_type() != NULL + && cap_arg->type()->integer_type()->bits() > uintptr_bits) + have_big_args = true; ++parg; } @@ -7801,16 +7811,26 @@ if (is_slice) { if (cap_arg == NULL) - call = Runtime::make_call(Runtime::MAKESLICE1, loc, 2, type_arg, - len_arg); + call = Runtime::make_call((have_big_args + ? Runtime::MAKESLICE1BIG + : Runtime::MAKESLICE1), + loc, 2, type_arg, len_arg); else - call = Runtime::make_call(Runtime::MAKESLICE2, loc, 3, type_arg, - len_arg, cap_arg); + call = Runtime::make_call((have_big_args + ? Runtime::MAKESLICE2BIG + : Runtime::MAKESLICE2), + loc, 3, type_arg, len_arg, cap_arg); } else if (is_map) - call = Runtime::make_call(Runtime::MAKEMAP, loc, 2, type_arg, len_arg); + call = Runtime::make_call((have_big_args + ? Runtime::MAKEMAPBIG + : Runtime::MAKEMAP), + loc, 2, type_arg, len_arg); else if (is_chan) - call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg); + call = Runtime::make_call((have_big_args + ? Runtime::MAKECHANBIG + : Runtime::MAKECHAN), + loc, 2, type_arg, len_arg); else go_unreachable(); diff -r df952f89b74e go/runtime.def --- a/go/runtime.def Tue Feb 07 21:29:07 2012 -0800 +++ b/go/runtime.def Tue Feb 07 22:13:53 2012 -0800 @@ -72,10 +72,16 @@ DEF_GO_RUNTIME(MAKESLICE1, "__go_make_slice1", P2(TYPE, UINTPTR), R1(SLICE)) DEF_GO_RUNTIME(MAKESLICE2, "__go_make_slice2", P3(TYPE, UINTPTR, UINTPTR), R1(SLICE)) +DEF_GO_RUNTIME(MAKESLICE1BIG, "__go_make_slice1_big", P2(TYPE, UINT64), + R1(SLICE)) +DEF_GO_RUNTIME(MAKESLICE2BIG, "__go_make_slice2_big", P3(TYPE, UINT64, UINT64), + R1(SLICE)) // Make a map. DEF_GO_RUNTIME(MAKEMAP, "__go_new_map", P2(MAPDESCRIPTOR, UINTPTR), R1(MAP)) +DEF_GO_RUNTIME(MAKEMAPBIG, "__go_new_map_big", P2(MAPDESCRIPTOR, UINT64), + R1(MAP)) // Build a map from a composite literal. DEF_GO_RUNTIME(CONSTRUCT_MAP, "__go_construct_map", @@ -116,6 +122,7 @@ // Make a channel. DEF_GO_RUNTIME(MAKECHAN, "__go_new_channel", P2(TYPE, UINTPTR), R1(CHAN)) +DEF_GO_RUNTIME(MAKECHANBIG, "__go_new_channel_big", P2(TYPE, UINT64), R1(CHAN)) // Get the length of a channel (the number of unread values). DEF_GO_RUNTIME(CHAN_LEN, "__go_chan_len", P1(CHAN), R1(INT)) diff -r df952f89b74e libgo/runtime/chan.c --- a/libgo/runtime/chan.c Tue Feb 07 21:29:07 2012 -0800 +++ b/libgo/runtime/chan.c Tue Feb 07 22:13:53 2012 -0800 @@ -130,6 +130,12 @@ return runtime_makechan_c(t, hint); } +Hchan* +__go_new_channel_big(ChanType *t, uint64 hint) +{ + return runtime_makechan_c(t, hint); +} + /* * generic single channel send/recv * if the bool pointer is nil, diff -r df952f89b74e libgo/runtime/go-make-slice.c --- a/libgo/runtime/go-make-slice.c Tue Feb 07 21:29:07 2012 -0800 +++ b/libgo/runtime/go-make-slice.c Tue Feb 07 22:13:53 2012 -0800 @@ -57,3 +57,27 @@ { return __go_make_slice2 (td, len, len); } + +struct __go_open_array +__go_make_slice2_big (const struct __go_type_descriptor *td, uint64_t len, + uint64_t cap) +{ + uintptr_t slen; + uintptr_t scap; + + slen = (uintptr_t) len; + if ((uint64_t) slen != len) + runtime_panicstring ("makeslice: len out of range"); + + scap = (uintptr_t) cap; + if ((uint64_t) scap != cap) + runtime_panicstring ("makeslice: cap out of range"); + + return __go_make_slice2 (td, slen, scap); +} + +struct __go_open_array +__go_make_slice1_big (const struct __go_type_descriptor *td, uint64_t len) +{ + return __go_make_slice2_big (td, len, len); +} diff -r df952f89b74e libgo/runtime/go-new-map.c --- a/libgo/runtime/go-new-map.c Tue Feb 07 21:29:07 2012 -0800 +++ b/libgo/runtime/go-new-map.c Tue Feb 07 22:13:53 2012 -0800 @@ -125,3 +125,17 @@ __builtin_memset (ret->__buckets, 0, entries * sizeof (void *)); return ret; } + +/* Allocate a new map when the argument to make is a large type. */ + +struct __go_map * +__go_new_map_big (const struct __go_map_descriptor *descriptor, + uint64_t entries) +{ + uintptr_t sentries; + + sentries = (uintptr_t) entries; + if ((uint64_t) sentries != entries) + runtime_panicstring ("map size out of range"); + return __go_new_map (descriptor, sentries); +}