From patchwork Thu Jun 7 23:39:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luc Van Oostenryck X-Patchwork-Id: 10453665 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 698AD60375 for ; Thu, 7 Jun 2018 23:41:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5B6EF298A4 for ; Thu, 7 Jun 2018 23:41:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 500222996E; Thu, 7 Jun 2018 23:41:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 48A122995E for ; Thu, 7 Jun 2018 23:41:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752268AbeFGXlo (ORCPT ); Thu, 7 Jun 2018 19:41:44 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:55764 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752260AbeFGXlm (ORCPT ); Thu, 7 Jun 2018 19:41:42 -0400 Received: by mail-wm0-f68.google.com with SMTP id v16-v6so212809wmh.5 for ; Thu, 07 Jun 2018 16:41:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Jl+WiPAKDh8FzerwxaSINnmTA8BBl2SiwR4byrvz4jU=; b=KueHshWpZugTjQRD3pD4R9XZ9osooR7n5dnXBIf6or1rzwDdR2JYRX0YxHwKWxkz9S 8XiBkW85wpRqSQAmA3B21XLNknGcPPSqp2S7PgJRGNK2FYAIdyvt2r4J1bHaUT9pJkV9 JQQpPxDjHipjmLG7DeOF9z/16EvKvtYlp52x0YIWwDB1HykXUkSrp0OaD/q+2dHjDAaA xAaRx4u2NQB9WDvyJg7OH6/8c/2hRJ/w/s4mSqumRZIN0lTaddQHExUHcZETaKUzsY10 hJQ9lSEq720HqewG7TBEUDWonCbw3IBm1WU6zyjLx3Gz20ei5aFmT6XugWoxqIVJIipz 3t7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Jl+WiPAKDh8FzerwxaSINnmTA8BBl2SiwR4byrvz4jU=; b=Fd/xjPVQaljRe7uLTmQWQKOK0KsX7eHvNTfxxgJszX0ETLxTEKNwBa9RpDJdaVlGLr QoPJFm+nE4lqIJ7qnQmrBtIapFfI7Ee1sQTdgVSUSyAc5OrBR9eMNV/PbIqlRxjCDe9r UjVa9xIBJjzd9NuD4+GuM8I2UWmIXQEI/kiMNFHBhSy6Sa2F5ACnONvYd4SDCPxem9wI lcmqyxnoNHFgpy3+9WYC9HMRtNsS6iXvizlF/TeE+gCWRsE9u5pI6xsxM4B/nmBly58U Yq1jpdKO0wUMi1zWtpXUlaroS/WTfSYt5dLHiZq2D0zZuk12GN3GO07vm9n5HYGkATq/ YohA== X-Gm-Message-State: APt69E0916enk1+6Pk6LKFckYjeznFwN/BnXlNQWjvyjE6XSaPfkMi1p xVL12W+flTquu5feUFGfnaG70oka X-Google-Smtp-Source: ADUXVKKMSjbELuTXt3lx0Gz9sN+tXRnzjebvZyf4lNOYxCvOZvrm/Si7KbQeILZIwJleutFaPbsf7A== X-Received: by 2002:a50:a621:: with SMTP id d30-v6mr4414994edc.173.1528414901311; Thu, 07 Jun 2018 16:41:41 -0700 (PDT) Received: from localhost.localdomain ([2a02:a03f:4108:7200:48ec:50ae:df82:46f4]) by smtp.gmail.com with ESMTPSA id z11-v6sm28517802edh.60.2018.06.07.16.41.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 07 Jun 2018 16:41:40 -0700 (PDT) From: Luc Van Oostenryck To: linux-sparse@vger.kernel.org Cc: Miroslav Benes , Kees Cook , Luc Van Oostenryck Subject: [PATCH 3/3] builtin: add support for __builtin_{add, sub, mul}_overflow(), ... Date: Fri, 8 Jun 2018 01:39:33 +0200 Message-Id: <20180607233933.38189-4-luc.vanoostenryck@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180607233933.38189-1-luc.vanoostenryck@gmail.com> References: <20180607233933.38189-1-luc.vanoostenryck@gmail.com> Sender: linux-sparse-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sparse@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP It seems they will be used in the kernel so add them. Unlike __builtin_uadd_overflow() and friends, these don't take a fixed type and thus can't simply be declared but need their own evaluate() method to do the type checking. Note: of course, no expansion is done on them. Signed-off-by: Luc Van Oostenryck --- builtin.c | 76 +++++++++++ validation/builtin-overflow.c | 246 ++++++++++++++++++++++++++++++++++ 2 files changed, 322 insertions(+) create mode 100644 validation/builtin-overflow.c diff --git a/builtin.c b/builtin.c index 9fae8f2cc..9d7743927 100644 --- a/builtin.c +++ b/builtin.c @@ -251,6 +251,76 @@ static struct symbol_op fp_unop_op = { }; +static int args_overflow(struct expression *expr) +{ + return eval_args(expr, 3); +} + +static int evaluate_overflow_gen(struct expression *expr, int ptr) +{ + struct expression *arg; + int n = 0; + + /* there will be exactly 3; we'd already verified that */ + FOR_EACH_PTR(expr->args, arg) { + struct symbol *type; + + n++; + if (!arg || !(type = arg->ctype)) + return 0; + // 1st & 2nd args must be a basic integer type + // 3rd arg must be a pointer to such a type. + if (n == 3 && ptr) { + if (type->type == SYM_NODE) + type = type->ctype.base_type; + if (!type) + return 0; + if (type->type != SYM_PTR) + goto err; + type = type->ctype.base_type; + if (!type) + return 0; + } + if (type->type == SYM_NODE) + type = type->ctype.base_type; + if (!type) + return 0; + if (type->ctype.base_type != &int_type || type == &bool_ctype) + goto err; + } END_FOR_EACH_PTR(arg); + + // the builtin returns a bool + expr->ctype = &bool_ctype; + return 1; + +err: + sparse_error(arg->pos, "invalid type for argument %d:", n); + info(arg->pos, " %s", show_typename(arg->ctype)); + expr->ctype = &bad_ctype; + return 0; +} + +static int evaluate_overflow(struct expression *expr) +{ + return evaluate_overflow_gen(expr, 1); +} + +static struct symbol_op overflow_op = { + .args = args_overflow, + .evaluate = evaluate_overflow, +}; + +static int evaluate_overflow_p(struct expression *expr) +{ + return evaluate_overflow_gen(expr, 0); +} + +static struct symbol_op overflow_p_op = { + .args = args_overflow, + .evaluate = evaluate_overflow_p, +}; + + /* * Builtin functions */ @@ -275,6 +345,12 @@ static struct sym_init { { "__builtin_isnan", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, { "__builtin_isnormal", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, { "__builtin_signbit", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, + { "__builtin_add_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op }, + { "__builtin_sub_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op }, + { "__builtin_mul_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op }, + { "__builtin_add_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op }, + { "__builtin_sub_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op }, + { "__builtin_mul_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op }, { NULL, NULL, 0 } }; diff --git a/validation/builtin-overflow.c b/validation/builtin-overflow.c new file mode 100644 index 000000000..867eb42f5 --- /dev/null +++ b/validation/builtin-overflow.c @@ -0,0 +1,246 @@ +enum e { OK }; +typedef _Bool bool; + +static int test(int i, long l, long long ll, enum e e, bool b, void *p) +{ + int rc = 0; + + // should be OK + rc += __builtin_add_overflow(i, i, &i); + rc += __builtin_add_overflow(l, i, &i); + rc += __builtin_add_overflow(i, l, &i); + rc += __builtin_add_overflow(i, i, &l); + rc += __builtin_add_overflow(ll, i, &i); + rc += __builtin_add_overflow(i, ll, &i); + rc += __builtin_add_overflow(i, i, &ll); + + rc += __builtin_add_overflow_p(i, i, i); + rc += __builtin_add_overflow_p(l, i, i); + rc += __builtin_add_overflow_p(i, l, i); + rc += __builtin_add_overflow_p(i, i, l); + rc += __builtin_add_overflow_p(ll, i, i); + rc += __builtin_add_overflow_p(i, ll, i); + rc += __builtin_add_overflow_p(i, i, ll); + + rc += __builtin_sub_overflow(i, i, &i); + rc += __builtin_sub_overflow(l, i, &i); + rc += __builtin_sub_overflow(i, l, &i); + rc += __builtin_sub_overflow(i, i, &l); + rc += __builtin_sub_overflow(ll, i, &i); + rc += __builtin_sub_overflow(i, ll, &i); + rc += __builtin_sub_overflow(i, i, &ll); + + rc += __builtin_sub_overflow_p(i, i, i); + rc += __builtin_sub_overflow_p(l, i, i); + rc += __builtin_sub_overflow_p(i, l, i); + rc += __builtin_sub_overflow_p(i, i, l); + rc += __builtin_sub_overflow_p(ll, i, i); + rc += __builtin_sub_overflow_p(i, ll, i); + rc += __builtin_sub_overflow_p(i, i, ll); + + rc += __builtin_mul_overflow(i, i, &i); + rc += __builtin_mul_overflow(l, i, &i); + rc += __builtin_mul_overflow(i, l, &i); + rc += __builtin_mul_overflow(i, i, &l); + rc += __builtin_mul_overflow(ll, i, &i); + rc += __builtin_mul_overflow(i, ll, &i); + rc += __builtin_mul_overflow(i, i, &ll); + + rc += __builtin_mul_overflow_p(i, i, i); + rc += __builtin_mul_overflow_p(l, i, i); + rc += __builtin_mul_overflow_p(i, l, i); + rc += __builtin_mul_overflow_p(i, i, l); + rc += __builtin_mul_overflow_p(ll, i, i); + rc += __builtin_mul_overflow_p(i, ll, i); + rc += __builtin_mul_overflow_p(i, i, ll); + + // should be KO + rc += __builtin_add_overflow(); + rc += __builtin_add_overflow(i); + rc += __builtin_add_overflow(i, i); + rc += __builtin_add_overflow(i, i, &i, i); + rc += __builtin_add_overflow(e, i, &i); + rc += __builtin_add_overflow(i, e, &i); + rc += __builtin_add_overflow(i, i, &e); + rc += __builtin_add_overflow(b, i, &i); + rc += __builtin_add_overflow(i, b, &i); + rc += __builtin_add_overflow(i, i, &b); + rc += __builtin_add_overflow(i, i, p); + + rc += __builtin_add_overflow_p(); + rc += __builtin_add_overflow_p(i); + rc += __builtin_add_overflow_p(i, i); + rc += __builtin_add_overflow_p(i, i, i, i); + rc += __builtin_add_overflow_p(e, i, i); + rc += __builtin_add_overflow_p(i, e, i); + rc += __builtin_add_overflow_p(i, i, e); + rc += __builtin_add_overflow_p(b, i, i); + rc += __builtin_add_overflow_p(i, b, i); + rc += __builtin_add_overflow_p(i, i, b); + rc += __builtin_add_overflow_p(i, i, p); + + rc += __builtin_sub_overflow(); + rc += __builtin_sub_overflow(i); + rc += __builtin_sub_overflow(i, i); + rc += __builtin_sub_overflow(i, i, &i, i); + rc += __builtin_sub_overflow(e, i, &i); + rc += __builtin_sub_overflow(i, e, &i); + rc += __builtin_sub_overflow(i, i, &e); + rc += __builtin_sub_overflow(b, i, &i); + rc += __builtin_sub_overflow(i, b, &i); + rc += __builtin_sub_overflow(i, i, &b); + rc += __builtin_sub_overflow(i, i, p); + + rc += __builtin_sub_overflow_p(); + rc += __builtin_sub_overflow_p(i); + rc += __builtin_sub_overflow_p(i, i); + rc += __builtin_sub_overflow_p(i, i, i, i); + rc += __builtin_sub_overflow_p(e, i, i); + rc += __builtin_sub_overflow_p(i, e, i); + rc += __builtin_sub_overflow_p(i, i, e); + rc += __builtin_sub_overflow_p(b, i, i); + rc += __builtin_sub_overflow_p(i, b, i); + rc += __builtin_sub_overflow_p(i, i, b); + rc += __builtin_sub_overflow_p(i, i, p); + + rc += __builtin_mul_overflow(); + rc += __builtin_mul_overflow(i); + rc += __builtin_mul_overflow(i, i); + rc += __builtin_mul_overflow(i, i, &i, i); + rc += __builtin_mul_overflow(e, i, &i); + rc += __builtin_mul_overflow(i, e, &i); + rc += __builtin_mul_overflow(i, i, &e); + rc += __builtin_mul_overflow(b, i, &i); + rc += __builtin_mul_overflow(i, b, &i); + rc += __builtin_mul_overflow(i, i, &b); + rc += __builtin_mul_overflow(i, i, p); + + rc += __builtin_mul_overflow_p(); + rc += __builtin_mul_overflow_p(i); + rc += __builtin_mul_overflow_p(i, i); + rc += __builtin_mul_overflow_p(i, i, i, i); + rc += __builtin_mul_overflow_p(e, i, i); + rc += __builtin_mul_overflow_p(i, e, i); + rc += __builtin_mul_overflow_p(i, i, e); + rc += __builtin_mul_overflow_p(b, i, i); + rc += __builtin_mul_overflow_p(i, b, i); + rc += __builtin_mul_overflow_p(i, i, b); + rc += __builtin_mul_overflow_p(i, i, p); + + return rc; +} + +/* + * check-name: builtin-overflow + * + * check-error-start +builtin-overflow.c:58:37: error: not enough arguments for __builtin_add_overflow +builtin-overflow.c:59:37: error: not enough arguments for __builtin_add_overflow +builtin-overflow.c:60:37: error: not enough arguments for __builtin_add_overflow +builtin-overflow.c:61:37: error: too many arguments for __builtin_add_overflow +builtin-overflow.c:62:38: error: invalid type for argument 1: +builtin-overflow.c:62:38: int enum e [signed] e +builtin-overflow.c:63:41: error: invalid type for argument 2: +builtin-overflow.c:63:41: int enum e [signed] e +builtin-overflow.c:64:45: error: invalid type for argument 3: +builtin-overflow.c:64:45: int enum e * +builtin-overflow.c:65:38: error: invalid type for argument 1: +builtin-overflow.c:65:38: bool [unsigned] [usertype] b +builtin-overflow.c:66:41: error: invalid type for argument 2: +builtin-overflow.c:66:41: bool [unsigned] [usertype] b +builtin-overflow.c:67:45: error: invalid type for argument 3: +builtin-overflow.c:67:45: bool * +builtin-overflow.c:68:44: error: invalid type for argument 3: +builtin-overflow.c:68:44: void *p +builtin-overflow.c:70:39: error: not enough arguments for __builtin_add_overflow_p +builtin-overflow.c:71:39: error: not enough arguments for __builtin_add_overflow_p +builtin-overflow.c:72:39: error: not enough arguments for __builtin_add_overflow_p +builtin-overflow.c:73:39: error: too many arguments for __builtin_add_overflow_p +builtin-overflow.c:74:40: error: invalid type for argument 1: +builtin-overflow.c:74:40: int enum e [signed] [addressable] e +builtin-overflow.c:75:43: error: invalid type for argument 2: +builtin-overflow.c:75:43: int enum e [signed] [addressable] e +builtin-overflow.c:76:46: error: invalid type for argument 3: +builtin-overflow.c:76:46: int enum e [signed] [addressable] e +builtin-overflow.c:77:40: error: invalid type for argument 1: +builtin-overflow.c:77:40: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:78:43: error: invalid type for argument 2: +builtin-overflow.c:78:43: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:79:46: error: invalid type for argument 3: +builtin-overflow.c:79:46: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:80:46: error: invalid type for argument 3: +builtin-overflow.c:80:46: void *p +builtin-overflow.c:82:37: error: not enough arguments for __builtin_sub_overflow +builtin-overflow.c:83:37: error: not enough arguments for __builtin_sub_overflow +builtin-overflow.c:84:37: error: not enough arguments for __builtin_sub_overflow +builtin-overflow.c:85:37: error: too many arguments for __builtin_sub_overflow +builtin-overflow.c:86:38: error: invalid type for argument 1: +builtin-overflow.c:86:38: int enum e [signed] [addressable] e +builtin-overflow.c:87:41: error: invalid type for argument 2: +builtin-overflow.c:87:41: int enum e [signed] [addressable] e +builtin-overflow.c:88:45: error: invalid type for argument 3: +builtin-overflow.c:88:45: int enum e * +builtin-overflow.c:89:38: error: invalid type for argument 1: +builtin-overflow.c:89:38: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:90:41: error: invalid type for argument 2: +builtin-overflow.c:90:41: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:91:45: error: invalid type for argument 3: +builtin-overflow.c:91:45: bool * +builtin-overflow.c:92:44: error: invalid type for argument 3: +builtin-overflow.c:92:44: void *p +builtin-overflow.c:94:39: error: not enough arguments for __builtin_sub_overflow_p +builtin-overflow.c:95:39: error: not enough arguments for __builtin_sub_overflow_p +builtin-overflow.c:96:39: error: not enough arguments for __builtin_sub_overflow_p +builtin-overflow.c:97:39: error: too many arguments for __builtin_sub_overflow_p +builtin-overflow.c:98:40: error: invalid type for argument 1: +builtin-overflow.c:98:40: int enum e [signed] [addressable] e +builtin-overflow.c:99:43: error: invalid type for argument 2: +builtin-overflow.c:99:43: int enum e [signed] [addressable] e +builtin-overflow.c:100:46: error: invalid type for argument 3: +builtin-overflow.c:100:46: int enum e [signed] [addressable] e +builtin-overflow.c:101:40: error: invalid type for argument 1: +builtin-overflow.c:101:40: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:102:43: error: invalid type for argument 2: +builtin-overflow.c:102:43: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:103:46: error: invalid type for argument 3: +builtin-overflow.c:103:46: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:104:46: error: invalid type for argument 3: +builtin-overflow.c:104:46: void *p +builtin-overflow.c:106:37: error: not enough arguments for __builtin_mul_overflow +builtin-overflow.c:107:37: error: not enough arguments for __builtin_mul_overflow +builtin-overflow.c:108:37: error: not enough arguments for __builtin_mul_overflow +builtin-overflow.c:109:37: error: too many arguments for __builtin_mul_overflow +builtin-overflow.c:110:38: error: invalid type for argument 1: +builtin-overflow.c:110:38: int enum e [signed] [addressable] e +builtin-overflow.c:111:41: error: invalid type for argument 2: +builtin-overflow.c:111:41: int enum e [signed] [addressable] e +builtin-overflow.c:112:45: error: invalid type for argument 3: +builtin-overflow.c:112:45: int enum e * +builtin-overflow.c:113:38: error: invalid type for argument 1: +builtin-overflow.c:113:38: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:114:41: error: invalid type for argument 2: +builtin-overflow.c:114:41: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:115:45: error: invalid type for argument 3: +builtin-overflow.c:115:45: bool * +builtin-overflow.c:116:44: error: invalid type for argument 3: +builtin-overflow.c:116:44: void *p +builtin-overflow.c:118:39: error: not enough arguments for __builtin_mul_overflow_p +builtin-overflow.c:119:39: error: not enough arguments for __builtin_mul_overflow_p +builtin-overflow.c:120:39: error: not enough arguments for __builtin_mul_overflow_p +builtin-overflow.c:121:39: error: too many arguments for __builtin_mul_overflow_p +builtin-overflow.c:122:40: error: invalid type for argument 1: +builtin-overflow.c:122:40: int enum e [signed] [addressable] e +builtin-overflow.c:123:43: error: invalid type for argument 2: +builtin-overflow.c:123:43: int enum e [signed] [addressable] e +builtin-overflow.c:124:46: error: invalid type for argument 3: +builtin-overflow.c:124:46: int enum e [signed] [addressable] e +builtin-overflow.c:125:40: error: invalid type for argument 1: +builtin-overflow.c:125:40: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:126:43: error: invalid type for argument 2: +builtin-overflow.c:126:43: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:127:46: error: invalid type for argument 3: +builtin-overflow.c:127:46: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:128:46: error: invalid type for argument 3: +builtin-overflow.c:128:46: void *p + * check-error-end + */