From patchwork Wed Sep 1 03:08:01 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 63336 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id DC843B7140 for ; Wed, 1 Sep 2010 13:08:26 +1000 (EST) Received: (qmail 22951 invoked by alias); 1 Sep 2010 03:08:23 -0000 Received: (qmail 22923 invoked by uid 22791); 1 Sep 2010 03:08:20 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, SPF_HELO_PASS, TW_CC, TW_HK, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (216.239.44.51) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 01 Sep 2010 03:08:14 +0000 Received: from wpaz37.hot.corp.google.com (wpaz37.hot.corp.google.com [172.24.198.101]) by smtp-out.google.com with ESMTP id o8138CJP004872 for ; Tue, 31 Aug 2010 20:08:12 -0700 Received: from pzk6 (pzk6.prod.google.com [10.243.19.134]) by wpaz37.hot.corp.google.com with ESMTP id o81389qA025694 for ; Tue, 31 Aug 2010 20:08:10 -0700 Received: by pzk6 with SMTP id 6so2744833pzk.3 for ; Tue, 31 Aug 2010 20:08:09 -0700 (PDT) Received: by 10.142.140.19 with SMTP id n19mr6743646wfd.224.1283310488201; Tue, 31 Aug 2010 20:08:08 -0700 (PDT) Received: from coign.google.com ([66.109.106.2]) by mx.google.com with ESMTPS id 33sm11861332wfg.9.2010.08.31.20.08.05 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 31 Aug 2010 20:08:07 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: [gccgo] Check make arguments Date: Tue, 31 Aug 2010 20:08:01 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This gccgo patch checks the arguments to the predeclared function make to make sure they are in-range and do not overflow. Committed to gccgo branch. Ian diff -r 5ee6d7ed6e13 go/expressions.cc --- a/go/expressions.cc Tue Aug 31 16:14:52 2010 -0700 +++ b/go/expressions.cc Tue Aug 31 19:48:00 2010 -0700 @@ -9886,10 +9886,11 @@ { if (this->args_ != NULL) { + Type_context context(Type::lookup_integer_type("int"), false); for (Expression_list::const_iterator pe = this->args_->begin(); pe != this->args_->end(); ++pe) - (*pe)->determine_type_no_context(); + (*pe)->determine_type(&context); } } diff -r 5ee6d7ed6e13 go/types.cc --- a/go/types.cc Tue Aug 31 16:14:52 2010 -0700 +++ b/go/types.cc Tue Aug 31 19:48:00 2010 -0700 @@ -3652,6 +3652,46 @@ } } +// Check that LEN, which has an arbitrary integer type, is +// non-negative and not more than the maximum value of BOUND_TYPE. +// Return a tree which performs this check. The return value may be +// NULL_TREE. CHECK is a set of checks so far which are or'ed into +// the result. + +tree +Array_type::check_make_arg(tree len, tree check, tree bound_type, + source_location location) +{ + tree len_type = TREE_TYPE(len); + tree ret = NULL_TREE; + if (!TYPE_UNSIGNED(len_type)) + ret = fold_build2_loc(location, LT_EXPR, boolean_type_node, + len, + fold_convert_loc(location, len_type, + integer_zero_node)); + if ((TYPE_UNSIGNED(len_type) && !TYPE_UNSIGNED(bound_type)) + || TYPE_SIZE(len_type) > TYPE_SIZE(bound_type)) + { + tree max = TYPE_MAX_VALUE(bound_type); + tree big = fold_build2_loc(location, GT_EXPR, boolean_type_node, + len, + fold_convert_loc(location, len_type, max)); + if (ret == NULL_TREE) + ret = big; + else + ret = fold_build2_loc(location, TRUTH_OR_EXPR, boolean_type_node, + ret, big); + } + + if (ret == NULL_TREE) + return check; + else if (check == NULL_TREE) + return ret; + else + return fold_build2_loc(location, TRUTH_OR_EXPR, boolean_type_node, + ret, check); +} + // Handle the builtin make function for a slice. tree @@ -3678,8 +3718,6 @@ if (element_type_tree == error_mark_node) return error_mark_node; tree element_size_tree = TYPE_SIZE_UNIT(element_type_tree); - element_size_tree = fold_convert_loc(location, TREE_TYPE(count_field), - element_size_tree); tree value = this->element_type_->get_init_tree(gogo, true); @@ -3690,30 +3728,76 @@ tree length_tree = args->front()->get_tree(context); if (length_tree == error_mark_node) return error_mark_node; - length_tree = ::convert(TREE_TYPE(count_field), length_tree); - length_tree = save_expr(length_tree); + if (!DECL_P(length_tree)) + length_tree = save_expr(length_tree); + if (!INTEGRAL_TYPE_P(TREE_TYPE(length_tree))) + length_tree = convert_to_integer(TREE_TYPE(count_field), length_tree); + + tree bad_index = Array_type::check_make_arg(length_tree, NULL_TREE, + TREE_TYPE(count_field), + location); + + length_tree = fold_convert_loc(location, TREE_TYPE(count_field), length_tree); tree capacity_tree; if (args->size() == 1) capacity_tree = length_tree; else { capacity_tree = args->back()->get_tree(context); - capacity_tree = ::convert(TREE_TYPE(count_field), capacity_tree); - capacity_tree = save_expr(capacity_tree); - capacity_tree = fold_build3_loc(location, COND_EXPR, - TREE_TYPE(count_field), - fold_build2_loc(location, - LT_EXPR, - boolean_type_node, - capacity_tree, - length_tree), - length_tree, - capacity_tree); - capacity_tree = save_expr(capacity_tree); - } - - tree size_tree = fold_build2_loc(location, MULT_EXPR, TREE_TYPE(count_field), - element_size_tree, capacity_tree); + if (capacity_tree == error_mark_node) + return error_mark_node; + if (!DECL_P(capacity_tree)) + capacity_tree = save_expr(capacity_tree); + if (!INTEGRAL_TYPE_P(TREE_TYPE(capacity_tree))) + capacity_tree = convert_to_integer(TREE_TYPE(count_field), + capacity_tree); + + bad_index = Array_type::check_make_arg(capacity_tree, bad_index, + TREE_TYPE(count_field), + location); + + tree chktype = (((TYPE_SIZE(TREE_TYPE(capacity_tree)) + > TYPE_SIZE(TREE_TYPE(length_tree))) + || ((TYPE_SIZE(TREE_TYPE(capacity_tree)) + == TYPE_SIZE(TREE_TYPE(length_tree))) + && TYPE_UNSIGNED(TREE_TYPE(capacity_tree)))) + ? TREE_TYPE(capacity_tree) + : TREE_TYPE(length_tree)); + tree chk = fold_build2_loc(location, LT_EXPR, boolean_type_node, + fold_convert_loc(location, chktype, + capacity_tree), + fold_convert_loc(location, chktype, + length_tree)); + if (bad_index == NULL_TREE) + bad_index = chk; + else + bad_index = fold_build2_loc(location, TRUTH_OR_EXPR, boolean_type_node, + bad_index, chk); + + capacity_tree = fold_convert_loc(location, TREE_TYPE(count_field), + capacity_tree); + } + + tree size_tree = fold_build2_loc(location, MULT_EXPR, sizetype, + element_size_tree, + fold_convert_loc(location, sizetype, + capacity_tree)); + + tree chk = fold_build2_loc(location, TRUTH_AND_EXPR, boolean_type_node, + fold_build2_loc(location, GT_EXPR, + boolean_type_node, + fold_convert_loc(location, + sizetype, + capacity_tree), + size_zero_node), + fold_build2_loc(location, LT_EXPR, + boolean_type_node, + size_tree, element_size_tree)); + if (bad_index == NULL_TREE) + bad_index = chk; + else + bad_index = fold_build2_loc(location, TRUTH_OR_EXPR, boolean_type_node, + bad_index, chk); tree space = context->gogo()->allocate_memory(this->element_type_, size_tree, location); @@ -3723,6 +3807,22 @@ space = fold_convert(TREE_TYPE(values_field), space); + if (bad_index != NULL_TREE && bad_index != boolean_false_node) + { + static tree bad_index_fndecl; + tree crash = Gogo::call_builtin(&bad_index_fndecl, + location, + "__go_bad_makeslice", + 0, + void_type_node); + TREE_NOTHROW(bad_index_fndecl) = 0; + TREE_THIS_VOLATILE(bad_index_fndecl) = 1; + space = build2(COMPOUND_EXPR, TREE_TYPE(space), + build3(COND_EXPR, void_type_node, + bad_index, crash, NULL_TREE), + space); + } + tree constructor = gogo->slice_constructor(type_tree, space, length_tree, capacity_tree); diff -r 5ee6d7ed6e13 go/types.h --- a/go/types.h Tue Aug 31 16:14:52 2010 -0700 +++ b/go/types.h Tue Aug 31 19:48:00 2010 -0700 @@ -1987,6 +1987,9 @@ tree get_length_tree(Gogo*); + static tree + check_make_arg(tree, tree, tree, source_location); + // A mapping from Type to tree, used to ensure that arrays of // identical types are identical. typedef std::tr1::unordered_map (size_t) -1 / element_size) + __go_panic_msg ("chan size out of range"); + alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); /* We use a circular buffer which means that when next_fetch == diff -r 5ee6d7ed6e13 libgo/runtime/go-new-map.c --- a/libgo/runtime/go-new-map.c Tue Aug 31 16:14:52 2010 -0700 +++ b/libgo/runtime/go-new-map.c Tue Aug 31 19:48:00 2010 -0700 @@ -5,6 +5,7 @@ license that can be found in the LICENSE file. */ #include "go-alloc.h" +#include "go-panic.h" #include "map.h" /* List of prime numbers, copied from libstdc++/src/hashtable.c. */ @@ -107,6 +108,9 @@ { struct __go_map *ret; + if ((size_t) (int) entries != entries) + __go_panic_msg ("map size out of range"); + if (entries == 0) entries = 5; else