From patchwork Fri Sep 2 14:08:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Lange X-Patchwork-Id: 931 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:ecc5:0:0:0:0:0 with SMTP id s5csp750935wro; Fri, 2 Sep 2022 07:10:30 -0700 (PDT) X-Google-Smtp-Source: AA6agR42d8OXzuPy9njVfMb/itSybGXxoInU7KmALv0vy5kVwbEDkgoYulcvm/ZZujSdGhQboOFe X-Received: by 2002:a17:907:84a:b0:733:735:2b1a with SMTP id ww10-20020a170907084a00b0073307352b1amr27052466ejb.290.1662127830332; Fri, 02 Sep 2022 07:10:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1662127830; cv=none; d=google.com; s=arc-20160816; b=gWfaOl1rs2m/Jk2Dxrvqob1TiD+lnX1KLl+918+3WlPbwrqy22seaF6OTcYXXCoIMq MADmTyATsegOGiewnbWS2GEvPqHfk4WL7E+MZD99Zww39Q25UJCKK3OE56vDRAQ9Asbh HMizeUK/otGZwT15EusAJpZfThqr5xZ+TcwfAKYpzOJjcDyUl4ulniK4oV7poQK31cc4 M6bls+pAwcyShTD4SsMR9wmMOwRZgwwtPBXEfp6iR/kUbhGSD5S9i6ztlNkUDxxqD/ZF 2hbMUhpyfaa7xc0CAA4DvhhMCoT0vokw/nrKeS4I9RgYCUEn53UqYbm4hkFZMbAoMg2u Fobw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:to:from:dkim-signature :dmarc-filter:delivered-to; bh=Q9ZSlmEPMtYgEuDjPoawT7tbUHynhJ8yn9zQOF1U0Kw=; b=zr9V0e45OTRsq92hSWi252WUUhkmkH+4eOv7PGYdFwN5CF90E9nBgDG/5FL6s9ywWc wJ3/zofzrr9rTRXhthx3xWZUkSyeaUKI3H2A3BZF75q1Kypqq4bL8PtQbjR3SZ62DSih 0xPEU8tqyXd55JNRGHKOH77Ffpbp85kfT35t+/qHNjKGxzjqo8/scp6sA4bts8xaTsFt Ngi3tawnjDuar8JMp3Xo7/w4kITDfPnYN/hPQCoX93BdXbI0OC4+cdqIodg3AIDm1h4W Tmb+xf04EG+b+uMDqDzLq+gsv3iiH8PpZSIQ2VURY8LzSZBHvb9+sI2VNmLIztJsvm6H 8wrA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@tim-lange.me header.s=default2108 header.b="HSb/f8EB"; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id cw18-20020a170906479200b0073160e42274si1763188ejc.718.2022.09.02.07.10.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Sep 2022 07:10:30 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=fail header.i=@tim-lange.me header.s=default2108 header.b="HSb/f8EB"; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B2A63385828B for ; Fri, 2 Sep 2022 14:10:25 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from www523.your-server.de (www523.your-server.de [159.69.224.22]) by sourceware.org (Postfix) with ESMTPS id 2BA563858C54 for ; Fri, 2 Sep 2022 14:10:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2BA563858C54 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=tim-lange.me Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tim-lange.me DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tim-lange.me; s=default2108; h=Content-Transfer-Encoding:MIME-Version: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References; bh=Q9ZSlmEPMtYgEuDjPoawT7tbUHynhJ8yn9zQOF1U0Kw=; b=HSb/f8EBvIqD5o2JyQzX9m3OV5 eUToxDDYHZZTrn0QhY4P4VUDlEqqvvqkQeKT+1/I1wleZQYKIVAWMzU9/lBpgRbPXSKYAV+2F3BtL d8QPQlH/SPSsZf7d6KVo7TSh/0Iki4XkTmMEDQO5YflH/yFjNRiauvXz0nitye01J1SzT/VJUjreR up6+VbZl7ljLo+N7XJ/0v65i7hOSBLGpoD4s/yBYlxd1RJYlJbDUXolNEL2jyI/1K8C2Y/C6uwIQQ XrsfcxiOv2VQS1fGYpLifaS98/TQvWRK9eIhVoMTJft7Vvrf7M/DlOFxvD7BuSLY7nB56JcwNTLBy He6B5pFg==; Received: from sslproxy05.your-server.de ([78.46.172.2]) by www523.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1oU7Mt-000FQP-GK; Fri, 02 Sep 2022 16:09:59 +0200 Received: from [2a02:908:1861:d6a0::6b5] (helo=fedora..) by sslproxy05.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oU7Mt-000PcQ-8R; Fri, 02 Sep 2022 16:09:59 +0200 From: Tim Lange To: gcc-patches@gcc.gnu.org Subject: [PATCH 1/2] analyzer: return a concrete offset for cast_regions Date: Fri, 2 Sep 2022 16:08:33 +0200 Message-Id: <20220902140834.11636-1-mail@tim-lange.me> X-Mailer: git-send-email 2.37.2 MIME-Version: 1.0 X-Authenticated-Sender: mail@tim-lange.me X-Virus-Scanned: Clear (ClamAV 0.103.6/26646/Fri Sep 2 09:55:25 2022) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_INFOUSMEBIZ, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Tim Lange Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1742867351861787701?= X-GMAIL-MSGID: =?utf-8?q?1742867351861787701?= This patch fixes a bug where maybe_fold_sub_svalue did not fold the access of a single char from a string to a char when the offset was zero because get_relative_concrete_offset did return false for cast_regions. Regrtested on Linux x86_64. 2022-09-02 Tim Lange gcc/analyzer/ChangeLog: * region.cc (cast_region::get_relative_concrete_offset): New overloaded method. * region.h: Add cast_region::get_relative_concrete_offset. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/fold-string-to-char.c: New test. --- gcc/analyzer/region.cc | 10 ++++++++++ gcc/analyzer/region.h | 2 ++ gcc/testsuite/gcc.dg/analyzer/fold-string-to-char.c | 8 ++++++++ 3 files changed, 20 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/analyzer/fold-string-to-char.c diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc index f4aba6b9c88..9c8279b130d 100644 --- a/gcc/analyzer/region.cc +++ b/gcc/analyzer/region.cc @@ -1556,6 +1556,16 @@ cast_region::dump_to_pp (pretty_printer *pp, bool simple) const } } +/* Implementation of region::get_relative_concrete_offset vfunc + for cast_region. */ + +bool +cast_region::get_relative_concrete_offset (bit_offset_t *out) const +{ + *out = (int) 0; + return true; +} + /* class heap_allocated_region : public region. */ /* Implementation of region::dump_to_pp vfunc for heap_allocated_region. */ diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h index d37584b7285..34ce1fa1714 100644 --- a/gcc/analyzer/region.h +++ b/gcc/analyzer/region.h @@ -1087,6 +1087,8 @@ public: void accept (visitor *v) const final override; void dump_to_pp (pretty_printer *pp, bool simple) const final override; + bool get_relative_concrete_offset (bit_offset_t *out) const final override; + const region *get_original_region () const { return m_original_region; } private: diff --git a/gcc/testsuite/gcc.dg/analyzer/fold-string-to-char.c b/gcc/testsuite/gcc.dg/analyzer/fold-string-to-char.c new file mode 100644 index 00000000000..46139216bba --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/fold-string-to-char.c @@ -0,0 +1,8 @@ +#include "analyzer-decls.h" + +void test_1 (void) +{ + char str[] = "Hello"; + char *ptr = str; + __analyzer_eval (ptr[0] == 'H'); /* { dg-warning "TRUE" } */ +} From patchwork Fri Sep 2 14:08:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Lange X-Patchwork-Id: 932 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:ecc5:0:0:0:0:0 with SMTP id s5csp751368wro; Fri, 2 Sep 2022 07:11:14 -0700 (PDT) X-Google-Smtp-Source: AA6agR4oNg4+d76bHrYHkPCl6ZEuEtu0gkusKYXCgSMuzcGuvTq+i+yEGuUsU74laEpXNra/xjFu X-Received: by 2002:a17:906:d552:b0:750:59d0:7adb with SMTP id cr18-20020a170906d55200b0075059d07adbmr2683752ejc.25.1662127874734; Fri, 02 Sep 2022 07:11:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1662127874; cv=none; d=google.com; s=arc-20160816; b=e5jhB8ALUrQ/IK0E+qUWA7qBf3pNcaE9AzuJLkQbHGLz/zrg3jPGUjYVXNQCwItez3 UjVOOymYl7HrLJHNbigZ+V02YtdydWShDSzi7cCaGqIiT7WCKzOVDXElNKHXhedIlesb Fxa6Dx1Pk2V0cFTSUUaxZG+cSwBDxraCh5Ac/auH0ms7EwdZ1XvVO4xylu6GAp0M4+VV qAJO0HzYWbWd3IEZqznX/RGrfy2CqT76iGMZ48zzo1nCgsjNJsV6D4vNMxhTIuZugA25 FCWK40o05tI29DOBLgIL+TG+oiCySgN6NmYVe+9ljVFUM6mzpzJ2/iApMri85HBBOybu GBNg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:to:from :dkim-signature:dmarc-filter:delivered-to; bh=IjOMAlM99OwIPZLaQvuh4FFQm2aMgP3Acs5xfq/m4LU=; b=DmIUM36FfLW4tpW/axtLs/rmwOmNggxOOjj3Jc5zz5fKBTZT4oPCTWdww2dt0H/NQ2 NHrNkMCTFdNXlPy5ZkTsGLj5rvk8D78uKU25lz7Yk1l/+iHwliRBD+aCbddYinNdjgTh 5yFog8Loitnr8rQw/KggtGTgtP/+ceYrjspJN7TOmPq0IUGNhRKr0ZHqDVsIAw0LuICI Z9+tFjurg2Owz2dBrlzzJA3V79MHJSoVYNpZ3ECnUULp4P03Fj2G7dfA9K+ysflPNpY6 Gf4oAow4NheMQqSXAroQz+AI+3GypF/AWQ3Lrk7kZ9i59p3H42zwc7HUH4ZdtlKHHbdC 300w== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@tim-lange.me header.s=default2108 header.b=lzBcihs0; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id k18-20020a508ad2000000b00446206d0d41si1823969edk.401.2022.09.02.07.11.14 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Sep 2022 07:11:14 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=fail header.i=@tim-lange.me header.s=default2108 header.b=lzBcihs0; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 442F33858C33 for ; Fri, 2 Sep 2022 14:10:56 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from www523.your-server.de (www523.your-server.de [159.69.224.22]) by sourceware.org (Postfix) with ESMTPS id C67D43858C33 for ; Fri, 2 Sep 2022 14:10:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C67D43858C33 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=tim-lange.me Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tim-lange.me DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tim-lange.me; s=default2108; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID; bh=IjOMAlM99OwIPZLaQvuh4FFQm2aMgP3Acs5xfq/m4LU=; b=lzBcihs07HfcnIVaRtjzABvxv6 Yhb+7msgcoBof0xrIlN+W1P08lnrnESmNKuOTgeEJ/iwSFo3sky4ZPPNExUTJVqvxvVsQ/K/aI8UJ HyPiUBcLiBO10xo9YmNn6WA4yPgGyfosj67xReEeva+mI/nF98gsV2Xx996D21WcKT3G32E+z7IT1 n6Rv7hO7XNXO0+YBVjeowgaIg4P+Rcg4vIeGKWOfpHiV/nUbG1mGTK6+XSXcCvBHCtQPklPoNa/uw m1jF+VthNUfwl16dquirERLqO8Ef8w1YgjTZ3KRv7fZ/Bx7u0iMf6ssOpD2YBIhhE98YY/Qz4VVJg YXFvQSjw==; Received: from sslproxy05.your-server.de ([78.46.172.2]) by www523.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1oU7Mv-000FQs-SN; Fri, 02 Sep 2022 16:10:01 +0200 Received: from [2a02:908:1861:d6a0::6b5] (helo=fedora..) by sslproxy05.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oU7Mv-000PcQ-Ku; Fri, 02 Sep 2022 16:10:01 +0200 From: Tim Lange To: gcc-patches@gcc.gnu.org Subject: [PATCH 2/2] analyzer: strcpy and strncpy semantics Date: Fri, 2 Sep 2022 16:08:34 +0200 Message-Id: <20220902140834.11636-2-mail@tim-lange.me> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20220902140834.11636-1-mail@tim-lange.me> References: <20220902140834.11636-1-mail@tim-lange.me> MIME-Version: 1.0 X-Authenticated-Sender: mail@tim-lange.me X-Virus-Scanned: Clear (ClamAV 0.103.6/26646/Fri Sep 2 09:55:25 2022) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_INFOUSMEBIZ, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Tim Lange Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1742867398596967908?= X-GMAIL-MSGID: =?utf-8?q?1742867398596967908?= Hi, below is my patch for the strcpy and strncpy semantics inside the analyzer, enabling the out-of-bounds checker to also complain about overflows caused by those two functions. As the plan is to reason about the inequality of symbolic values in the future, I decided to use eval_condition to compare the number of bytes and the string size for strncpy [0]. - Tim [0] instead of only trying to handle cases where svalues are constant; which was how I did it in an earlier draft discussed off-list. This patch adds modelling for the semantics of strcpy and strncpy in the simple case where the analyzer is able to reason about the inequality of the size argument and the string size. Regrtested on Linux x86_64. 2022-09-02 Tim Lange gcc/analyzer/ChangeLog: * region-model-impl-calls.cc (region_model::impl_call_strncpy): New function. * region-model.cc (region_model::on_call_pre): Add call to impl_call_strncpy. (region_model::get_string_size): New function. * region-model.h (class region_model): Add impl_call_strncpy and get_string_size. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/out-of-bounds-4.c: New test. * gcc.dg/analyzer/strcpy-3.c: New test. * gcc.dg/analyzer/strncpy-1.c: New test. --- gcc/analyzer/region-model-impl-calls.cc | 62 ++++++++- gcc/analyzer/region-model.cc | 33 +++++ gcc/analyzer/region-model.h | 4 + .../gcc.dg/analyzer/out-of-bounds-4.c | 122 ++++++++++++++++++ gcc/testsuite/gcc.dg/analyzer/strcpy-3.c | 23 ++++ gcc/testsuite/gcc.dg/analyzer/strncpy-1.c | 23 ++++ 6 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/out-of-bounds-4.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/strcpy-3.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/strncpy-1.c diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index 8eebd122d42..9f1ae020f4f 100644 --- a/gcc/analyzer/region-model-impl-calls.cc +++ b/gcc/analyzer/region-model-impl-calls.cc @@ -1019,13 +1019,69 @@ region_model::impl_call_strcpy (const call_details &cd) const svalue *dest_sval = cd.get_arg_svalue (0); const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0), cd.get_ctxt ()); + const svalue *src_sval = cd.get_arg_svalue (1); + const region *src_reg = deref_rvalue (src_sval, cd.get_arg_tree (1), + cd.get_ctxt ()); + const svalue *src_contents_sval = get_store_value (src_reg, + cd.get_ctxt ()); cd.maybe_set_lhs (dest_sval); - check_region_for_write (dest_reg, cd.get_ctxt ()); + /* Try to get the string size if SRC_REG is a string_region. */ + const svalue *copied_bytes_sval = get_string_size (src_reg); + /* Otherwise, check if the contents of SRC_REG is a string. */ + if (copied_bytes_sval->get_kind () == SK_UNKNOWN) + copied_bytes_sval = get_string_size (src_contents_sval); + + const region *sized_dest_reg + = m_mgr->get_sized_region (dest_reg, NULL_TREE, copied_bytes_sval); + set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ()); +} + +/* Handle the on_call_pre part of "strncpy" and "__builtin_strncpy_chk". */ - /* For now, just mark region's contents as unknown. */ - mark_region_as_unknown (dest_reg, cd.get_uncertainty ()); +void +region_model::impl_call_strncpy (const call_details &cd) +{ + const svalue *dest_sval = cd.get_arg_svalue (0); + const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0), + cd.get_ctxt ()); + const svalue *src_sval = cd.get_arg_svalue (1); + const region *src_reg = deref_rvalue (src_sval, cd.get_arg_tree (1), + cd.get_ctxt ()); + const svalue *src_contents_sval = get_store_value (src_reg, + cd.get_ctxt ()); + const svalue *num_bytes_sval = cd.get_arg_svalue (2); + + cd.maybe_set_lhs (dest_sval); + + const svalue *string_size_sval = get_string_size (src_reg); + if (string_size_sval->get_kind () == SK_UNKNOWN) + string_size_sval = get_string_size (src_contents_sval); + + /* strncpy copies until a zero terminator is reached or n bytes were copied. + Determine the lesser of both here. */ + tristate ts = eval_condition (string_size_sval, LT_EXPR, num_bytes_sval); + const svalue *copied_bytes_sval; + switch (ts.get_value ()) + { + case tristate::TS_TRUE: + copied_bytes_sval = string_size_sval; + break; + case tristate::TS_FALSE: + copied_bytes_sval = num_bytes_sval; + break; + case tristate::TS_UNKNOWN: + copied_bytes_sval + = m_mgr->get_or_create_unknown_svalue (size_type_node); + break; + default: + gcc_unreachable (); + } + + const region *sized_dest_reg = m_mgr->get_sized_region (dest_reg, NULL_TREE, + copied_bytes_sval); + set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ()); } /* Handle the on_call_pre part of "strlen". */ diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index ec29be259b5..c87c79e3f1b 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -1858,6 +1858,10 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt, case BUILT_IN_STRCPY_CHK: impl_call_strcpy (cd); return false; + case BUILT_IN_STRNCPY: + case BUILT_IN_STRNCPY_CHK: + impl_call_strncpy (cd); + return false; case BUILT_IN_STRLEN: impl_call_strlen (cd); return false; @@ -3218,6 +3222,35 @@ region_model::get_capacity (const region *reg) const return m_mgr->get_or_create_unknown_svalue (sizetype); } +/* Return the string size, including the 0-terminator, if SVAL is a + constant_svalue holding a string. Otherwise, return an unknown_svalue. */ + +const svalue * +region_model::get_string_size (const svalue *sval) const +{ + tree cst = sval->maybe_get_constant (); + if (!cst || TREE_CODE (cst) != STRING_CST) + return m_mgr->get_or_create_unknown_svalue (size_type_node); + + tree out = build_int_cst (size_type_node, TREE_STRING_LENGTH (cst)); + return m_mgr->get_or_create_constant_svalue (out); +} + +/* Return the string size, including the 0-terminator, if REG is a + string_region. Otherwise, return an unknown_svalue. */ + +const svalue * +region_model::get_string_size (const region *reg) const +{ + const string_region *str_reg = dyn_cast (reg); + if (!str_reg) + return m_mgr->get_or_create_unknown_svalue (size_type_node); + + tree cst = str_reg->get_string_cst (); + tree out = build_int_cst (size_type_node, TREE_STRING_LENGTH (cst)); + return m_mgr->get_or_create_constant_svalue (out); +} + /* If CTXT is non-NULL, use it to warn about any problems accessing REG, using DIR to determine if this access is a read or write. */ diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 7ce832f6ce4..a6a92d46d91 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -634,6 +634,7 @@ class region_model void impl_call_realloc (const call_details &cd); void impl_call_strchr (const call_details &cd); void impl_call_strcpy (const call_details &cd); + void impl_call_strncpy (const call_details &cd); void impl_call_strlen (const call_details &cd); void impl_call_operator_new (const call_details &cd); void impl_call_operator_delete (const call_details &cd); @@ -793,6 +794,9 @@ class region_model const svalue *get_capacity (const region *reg) const; + const svalue *get_string_size (const svalue *sval) const; + const svalue *get_string_size (const region *reg) const; + /* Implemented in sm-malloc.cc */ void on_realloc_with_move (const call_details &cd, const svalue *old_ptr_sval, diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-4.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-4.c new file mode 100644 index 00000000000..382f0fb5ef4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-4.c @@ -0,0 +1,122 @@ +/* { dg-additional-options "-Wno-stringop-overflow -Wno-stringop-truncation" } */ +#include +#include +#include + +/* Wanalyzer-out-of-bounds tests for str(n)py-related overflows. + + The intra-procedural tests are all catched by Wstringop-overflow. + The inter-procedural out-of-bounds are only found by the analyzer. */ + +void test1 (void) +{ + char dst[5]; + strcpy (dst, "Hello"); /* { dg-line test1 } */ + + /* { dg-warning "overflow" "warning" { target *-*-* } test1 } */ + /* { dg-message "dst" "note" { target *-*-* } test1 } */ +} + +void test2 (void) +{ + char dst[6]; + strcpy (dst, "Hello"); +} + +void test3 (void) +{ + char dst[5]; + strncpy (dst, "Hello", 6); /* { dg-line test3 } */ + + /* { dg-warning "overflow" "warning" { target *-*-* } test3 } */ + /* { dg-message "dst" "note" { target *-*-* } test3 } */ +} + +void test4 (void) +{ + char dst[5]; + strncpy (dst, "Hello", 5); +} + +void test5 (void) +{ + char *src = "Hello"; + char dst[5]; + strcpy (dst, src); /* { dg-line test5 } */ + + /* { dg-warning "overflow" "warning" { target *-*-* } test5 } */ + /* { dg-message "dst" "note" { target *-*-* } test5 } */ +} + +void test6 (void) +{ + char *src = "Hello"; + char dst[6]; + strcpy (dst, src); +} + +void test7 (void) +{ + int n = 6; + char *src = "Hello"; + char dst[5]; + strncpy (dst, src, n); /* { dg-line test7 } */ + + /* { dg-warning "overflow" "warning" { target *-*-* } test7 } */ + /* { dg-message "dst" "note" { target *-*-* } test7 } */ +} + +void test8 (void) +{ + int n = 5; + char *src = "Hello"; + char dst[n]; + strncpy (dst, src, n); +} + +char *return_hello (void) +{ + return "hello"; +} + +void test9 (void) +{ + char *str = return_hello (); + if (!str) + return; + char dst[5]; + strcpy (dst, str); /* { dg-line test9 } */ + + /* { dg-warning "overflow" "warning" { target *-*-* } test9 } */ + /* { dg-message "dst" "note" { target *-*-* } test9 } */ +} + +void test10 (void) +{ + char *str = return_hello (); + if (!str) + return; + char dst[6]; + strcpy (dst, str); +} + +void test11 (void) +{ + char *str = return_hello (); + if (!str) + return; + char dst[5]; + strncpy (dst, str, 6); /* { dg-line test11 } */ + + /* { dg-warning "overflow" "warning" { target *-*-* } test11 } */ + /* { dg-message "dst" "note" { target *-*-* } test11 } */ +} + +void test12 (void) +{ + char *str = return_hello (); + if (!str) + return; + char dst[6]; + strcpy (dst, str); +} diff --git a/gcc/testsuite/gcc.dg/analyzer/strcpy-3.c b/gcc/testsuite/gcc.dg/analyzer/strcpy-3.c new file mode 100644 index 00000000000..a38f9a7641f --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/strcpy-3.c @@ -0,0 +1,23 @@ +#include +#include "analyzer-decls.h" + +void test_1 (void) +{ + char str[] = "Hello"; + char buf[6]; + char *result = strcpy (buf, str); + __analyzer_describe (1, result); /* { dg-warning "region_svalue.*?'buf'" } */ + __analyzer_eval (result == buf); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[0] == 'H'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[1] == 'e'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[2] == 'l'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[3] == 'l'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[4] == 'o'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[5] == 0); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[0] == 'H'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[1] == 'e'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[2] == 'l'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[3] == 'l'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[4] == 'o'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[5] == 0); /* { dg-warning "TRUE" } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/strncpy-1.c b/gcc/testsuite/gcc.dg/analyzer/strncpy-1.c new file mode 100644 index 00000000000..ea051eb761a --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/strncpy-1.c @@ -0,0 +1,23 @@ +#include +#include "analyzer-decls.h" + +void test_1 (void) +{ + char str[] = "Hello"; + char buf[6]; + char *result = strncpy (buf, str, 6); + __analyzer_describe (1, result); /* { dg-warning "region_svalue.*?'buf'" } */ + __analyzer_eval (result == buf); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[0] == 'H'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[1] == 'e'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[2] == 'l'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[3] == 'l'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[4] == 'o'); /* { dg-warning "TRUE" } */ + __analyzer_eval (buf[5] == 0); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[0] == 'H'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[1] == 'e'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[2] == 'l'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[3] == 'l'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[4] == 'o'); /* { dg-warning "TRUE" } */ + __analyzer_eval (result[5] == 0); /* { dg-warning "TRUE" } */ +}