This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gccgo] Verify that array lengths are reasonable


This patch adds support to gccgo for verifying that array lengths are
reasonable, rather than just accepting any old thing and crashing later.
Committed to gccgo branch.

Ian

diff -r c59e94784c63 go/types.cc
--- a/go/types.cc	Tue Aug 31 15:01:07 2010 -0700
+++ b/go/types.cc	Tue Aug 31 15:50:24 2010 -0700
@@ -3363,6 +3363,98 @@
   return TRAVERSE_CONTINUE;
 }
 
+// Check that the length is valid.
+
+bool
+Array_type::verify_length()
+{
+  if (this->length_ == NULL)
+    return true;
+  if (!this->length_->is_constant())
+    {
+      error_at(this->length_->location(), "array bound is not constant");
+      return false;
+    }
+
+  mpz_t val;
+
+  Type* t = this->length_->type();
+  if (t->integer_type() != NULL)
+    {
+      Type* vt;
+      mpz_init(val);
+      if (!this->length_->integer_constant_value(true, val, &vt))
+	{
+	  error_at(this->length_->location(),
+		   "array bound is not constant");
+	  mpz_clear(val);
+	  return false;
+	}
+    }
+  else if (t->float_type() != NULL)
+    {
+      Type* vt;
+      mpfr_t fval;
+      mpfr_init(fval);
+      if (!this->length_->float_constant_value(fval, &vt))
+	{
+	  error_at(this->length_->location(),
+		   "array bound is not constant");
+	  mpfr_clear(fval);
+	  return false;
+	}
+      if (!mpfr_integer_p(fval))
+	{
+	  error_at(this->length_->location(),
+		   "array bound truncated to integer");
+	  mpfr_clear(fval);
+	  return false;
+	}
+      mpz_init(val);
+      mpfr_get_z(val, fval, GMP_RNDN);
+      mpfr_clear(fval);
+    }
+  else
+    {
+      error_at(this->length_->location(), "array bound is not numeric");
+      return false;
+    }
+
+  if (mpz_sgn(val) < 0)
+    {
+      error_at(this->length_->location(), "negative array bound");
+      mpz_clear(val);
+      return false;
+    }
+
+  Type* int_type = Type::lookup_integer_type("int");
+  int tbits = int_type->integer_type()->bits();
+  int vbits = mpz_sizeinbase(val, 2);
+  if (vbits + 1 > tbits)
+    {
+      error_at(this->length_->location(), "array bound overflows");
+      mpz_clear(val);
+      return false;
+    }
+
+  mpz_clear(val);
+
+  return true;
+}
+
+// Verify the type.
+
+bool
+Array_type::do_verify()
+{
+  if (!this->verify_length())
+    {
+      this->length_ = Expression::make_error(this->length_->location());
+      return false;
+    }
+  return true;
+}
+
 // Array type hash code.
 
 unsigned int
diff -r c59e94784c63 go/types.h
--- a/go/types.h	Tue Aug 31 15:01:07 2010 -0700
+++ b/go/types.h	Tue Aug 31 15:50:24 2010 -0700
@@ -1944,6 +1944,9 @@
   do_traverse(Traverse* traverse);
 
   bool
+  do_verify();
+
+  bool
   do_has_pointer() const
   {
     return this->length_ == NULL || this->element_type_->has_pointer();
@@ -1978,6 +1981,9 @@
   do_export(Export*) const;
 
  private:
+  bool
+  verify_length();
+
   tree
   get_length_tree(Gogo*);
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]