This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gccgo] Verify that array lengths are reasonable
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org, gofrontend-dev at googlegroups dot com
- Date: Tue, 31 Aug 2010 15:53:36 -0700
- Subject: [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*);