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);
+}

Reply via email to