From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from NAM11-DM6-obe.outbound.protection.outlook.com (mail-dm6nam11olkn2083.outbound.protection.outlook.com [40.92.19.83]) by sourceware.org (Postfix) with ESMTPS id 6C44B38356A7 for ; Fri, 22 Jul 2022 15:55:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 6C44B38356A7 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=cYTYl9vWVATvpZhPWiSt9PtH7s0WSnoeZSyljhPAbEgYeejnZBUKIHXDd8UXOl+0+LSsZJ3wcVO8rRcDN/i6K4hrOOU49N/3JMd2U8uoHLebJxNHNVgL4cD7msG4LilE1rAcZ9xqhkAqKjKpnen2n89LqgCxYiLkrsvIDpI5zz1sAcsD4j/7m2ZIfd/M3q/+L8P74OMvRjLVWrxYH985rBGTCNYnoM+Y//gLBM/w3EfH7j7HrsZ2dDzd8A2E7MnGCZMlr/PPzeVlInrieAogOOa+Me0kxNKsqxigFo0FCeWly/WWPaMEOztRJkUFjddf5mC8WY7FiPH3Htz9uZlBfw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=mIrBpHbJg9/l9Ax0hh+Rrpism4lefg0utfpGLptmCQU=; b=J/4m/Vt5fO4wBZdi0bUt3cvuiffe3Ld13DXSHVONgskpenIzL4NK6j/OGiBeyFRhDtuLgA6KCECU16EsoJguZpu1MiSm+0S6Cxl6iInWbdPNCXo1BLDK9lGnWbR/YoL9z7DbsHpzPmNMwQOxclLm3U0KDiP0Ziev+jA1JEn0tVoHKl7bgmuXhZaTRmbPD2wXCYFwtIyMTk6vWG9Sgi0zsgVJ1e6sjChZ4Jq4jfbrUyLcwg2vFfF0oLKR0s6yp/OXqsPZxvFIzk685I72FdUpqNrWem4wEkGX/KXihVK+3aK/18Ygv2No41ChwJey9IiIYDpr5D2cfd7004TjISkrgg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none Received: from CY4PR1801MB1910.namprd18.prod.outlook.com (2603:10b6:910:79::14) by PH0PR18MB5019.namprd18.prod.outlook.com (2603:10b6:510:11e::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5458.19; Fri, 22 Jul 2022 15:55:41 +0000 Received: from CY4PR1801MB1910.namprd18.prod.outlook.com ([fe80::4d74:63e5:d5ee:3647]) by CY4PR1801MB1910.namprd18.prod.outlook.com ([fe80::4d74:63e5:d5ee:3647%2]) with mapi id 15.20.5438.021; Fri, 22 Jul 2022 15:55:40 +0000 From: Immad Mir To: gcc-patches@gcc.gnu.org Cc: dmalcolm@redhat.com, mirimnan017@gmail.com, Immad Mir Subject: [PATCH] Adding three new function attributes for static analysis of file descriptors Date: Fri, 22 Jul 2022 21:25:20 +0530 Message-ID: X-Mailer: git-send-email 2.25.1 Reply-To: mirimnan017@gmail.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain X-TMN: [lxWaHpZqPnj7LOxWmIohByZtFgVhKSRQAH83CqiCm9an6TtCAZOJvxCVSWSazlxw] X-ClientProxiedBy: PN0PR01CA0001.INDPRD01.PROD.OUTLOOK.COM (2603:1096:c01:4f::6) To CY4PR1801MB1910.namprd18.prod.outlook.com (2603:10b6:910:79::14) X-Microsoft-Original-Message-ID: <20220722155520.7806-1-mirimmad@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 56847dae-2293-49bb-bddb-08da6bfaa05e X-MS-Exchange-SLBlob-MailProps: LzDHi3doVoKWV2Y1+WrElphdCTfCxhpQO+ihwvejMH90vN8nZj064dqN5JJOj9WNIEVSTJz07YZrvm6e4oJRtcvBoNwxs6oBMwPYHIMi88rmRW/MiVDfN1ZuRGuod+KmLeqn1K3ccyvkY/l0ZzJq4dZjiGHLK157EeENH6IwG1YYDqpsBgCQwJ3rlR7n5b+P5jSxNfcv8snICgXEbOP3At2XE61qsLTguHApxvsLbJ6x6LCjNA8CVKSy0IFKFIJsYJy5bpRCxXtrFuJqYK/bvhiJIwXZqzOxVpnThcmPEI0iYp6+PK6XpPGIk+jdwzT2oOkScp2ndP4ky9caozjmuhukvj2BzGz7G1x9xYyygLmy5rtPscmY4XDORE+LSETP63SVVkdVTOVbN1iAR7r+eQ0eHb3OAf4hl3P+D25JHQhVEIewH+7MmFmC+ZtuC0VKF37tUCiQOWaZzbIdxAZLsxss4TdcKRVtfyLdZahg9XYFICEC/objJA9waVghwfMXaEQ2hM/gB8qFZfwo4BpfzAkALVvkWQ5/88+mls5Ic8MB97hGOUqn2v+uCIrgpa0+pw6Ots5OETr26HlFlzT59a6dgjAKz27C25YqJNr49En5xiHJ9GdxdkAPNgiYnOQgxj+ReHHJ6udmXykZPAyu/xkRXo8JDeXo2aaEbTv0h6o/34ZWr39FmX4AsYRlKGSMM19pLD9C+Pth+WOKFoAJD54ZRKKy0D3mawGHBMdmicU= X-MS-TrafficTypeDiagnostic: PH0PR18MB5019:EE_ X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 5inPG7MIdlQtjfs0+CJavhy0yWS7VMmiQvB3M9X3WL5AP0Zwlc2zPGeki1bIGh8oTNrIoRoS7HUb5ZT9o5BWqseyi0XqTkovLpHaIvfdV6INFTMnC6jIhXH64xNGdgS1puA0DS39eVfMY9BBfoJsIn4TJCFhNpjqXDr9/Qw3w61SQz/BEH6Sc0am2tgqwinaFXXAlfqiCqHWmBpjpEanibMntSYe6lFc/fELV6+WOmTBs9bV3l7RS6xTEyput+3Koop4FDM6iN20jVFjoDhYHWRDHwXMOF8y/SalsROxd2Pnr0BJ7XB8U2tDGz4v0GLuDRQb7qEljq0uQXeMTzd0aIIjM9BQfKT63XHawFhVjo0NRrNinLSNZ15LqzJBKDTcRkGZ7t8672Sen71tkJYSA6jCq3D/8OiVY/SQjyjd7z2FxyeBRSK7mZWvL2dOF94LR8quWtaCOFSWsAkI8gwpoWDzOqGDCapYuFMYQftgVi9b2m6sR0mbDOfJMeT8nRpCuEOlPl1A7tggKjohLmQD1Xrd2WWhU8YXhzMmlfT0ZDsVngI1z9jfrzEej1jJoXPkAW4bLAeV3yKxWU3ikcyDLyU7hcVzQUs6bYYAebf1/mg+YooXS+OtbPSOAAZseAMo X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?3Mp4wOboYQDCjiws9hoWMexdyWoKqJD9yglAIOCm8B/tFr6KZjAeEAiKZLIV?= =?us-ascii?Q?3nDscoBiVAaalwGTlxqMz8FSIcwWPbYdEB9EC4DWLBzS+sq870jQykh1hnWM?= =?us-ascii?Q?06lYBsS35XYXC140OxVZT/sgI8RK2L8uJpu5WyK7mQAxIAxAozTbGHcOS845?= =?us-ascii?Q?Utkv2Uw9lBW8q8SQHtQHVQy8datKeTAi9XfKb0rDP7ub4vCGWCF0zGXawukt?= =?us-ascii?Q?cWq1QQGduwcVlXso5/js2ZPV7qrFT0kvByi2nbTHt2o1RuhUP3DVv+pqqILS?= =?us-ascii?Q?XiVLQYC5vHcoZXgX/u8E3P4ar/h2/iG7kZGY284x2N6B7GdJzeKzj/BzIWnM?= =?us-ascii?Q?txLlUpdWaetY8pgexJlLeQ1Q1ZXbNUn7PhyuN3SXcKKM8ZMJB8Z/O5aCY1YJ?= =?us-ascii?Q?M1q02/pG2mZExWvS6DvieNxiNY9lG7DBR4C6U7fX47NbuAcugYxugEcWIZBP?= =?us-ascii?Q?l3m5QP6NPufq0IpdsrWZWJzoy7UtZ+jcuFP7M+5QQIGqDoMVvjTgi+iPHgkB?= =?us-ascii?Q?tCm1LbzZochrxYOL5xnwd4NhzejspA53imZqJMhbTzJQ7z5HZpZOnBEnzIGa?= =?us-ascii?Q?FqsSwVlo52GP9CjBITxnFFfWuOQbZPYMaHtLoSnnvrjLW9LfwqRqtqUlqP/X?= =?us-ascii?Q?eRCNUPxs63m141dnU+tDOgRphnSNNbSHZbsR9PdOPIvsuKBMMkbH1PaI3nDq?= =?us-ascii?Q?3vvCtUq9khwjSa/6jYIDJ9AK4wA2gPFlvWG+/qHB4vxF3J6ESjwm2/TvUdL5?= =?us-ascii?Q?YMlG92l2WRsc+whGhxeQUJFf8EUAGpz4hm3XfArR8KLTLeRyklwYuvknIOMC?= =?us-ascii?Q?wyusqt0Cs0hxvl93Ag+JUGg0U/33hXTpLMjWUYkSVQaIbjmT4qHXpUsyF0oH?= =?us-ascii?Q?dPQn9NpVAvHRwmxs7u0wpaXDF6KfN8B51YUAfrKRUkNrk30rm9kSLYOeks3O?= =?us-ascii?Q?vE6WwGNnLrewM6KeFWeegY4kRdcU8NJiYkh0TYswij7f+aRLx/ZxYDEKqWKL?= =?us-ascii?Q?9E7x2lbfgrmKo5nkUauS/xO/N/sTYO7ohE3AtqeW3lFkXy6VwMLcH+rB5Xjr?= =?us-ascii?Q?kaFpYyh1GnXmSBEiwEcnguaq/4qRn+kAAWFBVfxOStSQ8xHxtBW3KiORFNNL?= =?us-ascii?Q?KBsN6wBNJ+qI52MdtvJH2xm9pU9CJOBSAoOuiDsVIft6KgHCCpRAAoaTF/ot?= =?us-ascii?Q?EWQGZQm0PiA3aqfJnhYSJiQLg8Y0b32VXaTEpIZcc3Zd5ll53EQy3fClOLJF?= =?us-ascii?Q?FcLRvHvXi2wzzgL7GYeoVY9GjHb1lbEnk0/Zkr9NQ5SI3EIMvd6o/W4m29rE?= =?us-ascii?Q?5TBUz5zP/cpQiB/GqU3PLvwll92TgskbyQW/MgrN5KWZYQ=3D=3D?= X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 56847dae-2293-49bb-bddb-08da6bfaa05e X-MS-Exchange-CrossTenant-AuthSource: CY4PR1801MB1910.namprd18.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Jul 2022 15:55:40.7749 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR18MB5019 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, FREEMAIL_REPLYTO, FREEMAIL_REPLYTO_END_DIGIT, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_PASS, TXREP, T_FILL_THIS_FORM_SHORT 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: , X-List-Received-Date: Fri, 22 Jul 2022 15:55:47 -0000 This patch adds three new function attributes to GCC that are used for static analysis of usage of file descriptors: 1) __attribute__ ((fd_arg(N))): The attributes may be applied to a function= that takes an open file descriptor at refrenced argument N. It indicates that the passed filedescriptor must not have been closed. Therefore, when the analyzer is enabled with -fanalyzer, the analyzer may emit a -Wanalyzer-fd-use-after-close diagnostic if it detects a code path in which a function with this attribute is called with a closed file descriptor. The attribute also indicates that the file descriptor must have been checke= d for validity before usage. Therefore, analyzer may emit -Wanalyzer-fd-use-without-check diagnostic if it detects a code path in which a function with this attribute is called with a file descriptor that = has not been checked for validity. 2) __attribute__((fd_arg_read(N))): The attribute is identical to fd_arg, but with the additional requirement that it might read from the file descriptor, and thus, the file descriptor must not have been opened as write-only. The analyzer may emit a -Wanalyzer-access-mode-mismatch diagnostic if it detects a code path in which a function with this attribute is called on a file descriptor opened with O_WRONLY. 3) __attribute__((fd_arg_write(N))): The attribute is identical to fd_arg_r= ead except that the analyzer may emit a -Wanalyzer-access-mode-mismatch diagnos= tic if it detects a code path in which a function with this attribute is called on= a file descriptor opened with O_RDONLY. gcc/analyzer/ChangeLog: * sm-fd.cc (fd_param_diagnostic): New diagnostic class. (fd_access_mode_mismatch): Change inheritance from fd_diagnostic to fd_param_diagnostic. Add new overloaded constructor. (fd_use_after_close): Likewise. (unchecked_use_of_fd): Likewise and also change name to fd_use_without_che= ck. (double_close): Change name to fd_double_close. (enum access_directions): New. (fd_state_machine::on_stmt): Handle calls to function with the new three function attributes. (fd_state_machine::check_for_fd_attrs): New. (fd_state_machine::on_open): Use the new overloaded constructors of diagnostic classes. gcc/c-family/ChangeLog: * c-attribs.cc: (c_common_attribute_table): add three new attributes namely: fd_arg, fd_arg_read and fd_arg_write. (handle_fd_arg_attribute): New. gcc/ChangeLog: * doc/extend.texi: Add fd_arg, fd_arg_read and fd_arg_write under "Common Function Attributes" section. * doc/invoke.texi: Add docs to -Wanalyzer-fd-access-mode-mismatch, -Wanalyzer-use-after-close, -Wanalyzer-fd-use-without-check that these warnings may be emitted through usage of three function attributes used for static analysis of file descriptors namely fd_arg, fd_arg_read and fd_arg_write. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/fd-5.c: New test. * gcc.dg/analyzer/fd-4.c: Remove quotes around 'read-only' and 'write-only'. * c-c++-common/attr-fd.c: New test. Signed-off-by: Immad Mir --- gcc/analyzer/sm-fd.cc | 338 +++++++++++++++++++++------ gcc/c-family/c-attribs.cc | 31 +++ gcc/doc/extend.texi | 37 +++ gcc/doc/invoke.texi | 18 +- gcc/testsuite/c-c++-common/attr-fd.c | 18 ++ gcc/testsuite/gcc.dg/analyzer/fd-4.c | 8 +- gcc/testsuite/gcc.dg/analyzer/fd-5.c | 53 +++++ 7 files changed, 429 insertions(+), 74 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/attr-fd.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/fd-5.c diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index 8e4300b06e2..c3dac48509e 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -39,10 +39,13 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/analyzer-selftests.h"=0D #include "tristate.h"=0D #include "selftest.h"=0D +#include "stringpool.h"=0D +#include "attribs.h"=0D #include "analyzer/call-string.h"=0D #include "analyzer/program-point.h"=0D #include "analyzer/store.h"=0D #include "analyzer/region-model.h"=0D +#include "bitmap.h"=0D =0D #if ENABLE_ANALYZER=0D =0D @@ -59,6 +62,13 @@ enum access_mode WRITE_ONLY=0D };=0D =0D +enum access_directions=0D +{=0D + DIRS_READ_WRITE,=0D + DIRS_READ,=0D + DIRS_WRITE=0D +};=0D +=0D class fd_state_machine : public state_machine=0D {=0D public:=0D @@ -146,7 +156,7 @@ private: void check_for_open_fd (sm_context *sm_ctxt, const supernode *node,=0D const gimple *stmt, const gcall *call,=0D const tree callee_fndecl,=0D - enum access_direction access_fn) const;=0D + enum access_directions access_fn) const;=0D =0D void make_valid_transitions_on_condition (sm_context *sm_ctxt,=0D const supernode *node,=0D @@ -156,6 +166,10 @@ private: const supernode *node,=0D const gimple *stmt,=0D const svalue *lhs) const;=0D + void check_for_fd_attrs (sm_context *sm_ctxt, const supernode *node,=0D + const gimple *stmt, const gcall *call,=0D + const tree callee_fndecl, const char *attr_name= ,=0D + access_directions fd_attr_access_dir) const;=0D };=0D =0D /* Base diagnostic class relative to fd_state_machine. */=0D @@ -220,6 +234,70 @@ protected: tree m_arg;=0D };=0D =0D +class fd_param_diagnostic : public fd_diagnostic=0D +{=0D +public:=0D + fd_param_diagnostic (const fd_state_machine &sm, tree arg, tree callee_f= ndecl,=0D + const char *attr_name, int arg_idx)=0D + : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl),=0D + m_attr_name (attr_name), m_arg_idx (arg_idx)=0D + {=0D + }=0D +=0D + fd_param_diagnostic (const fd_state_machine &sm, tree arg, tree callee_f= ndecl)=0D + : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl),=0D + m_attr_name (NULL), m_arg_idx (-1)=0D + {=0D + }=0D + =0D + bool=0D + subclass_equal_p (const pending_diagnostic &base_other) const override=0D + {=0D + const fd_param_diagnostic &sub_other=0D + =3D (const fd_param_diagnostic &)base_other;=0D + return (same_tree_p (m_arg, sub_other.m_arg)=0D + && same_tree_p (m_callee_fndecl, sub_other.m_callee_fndecl)=0D + && m_arg_idx =3D=3D sub_other.m_arg_idx=0D + && ((m_attr_name)=0D + ? (strcmp (m_attr_name, sub_other.m_attr_name) =3D=3D = 0)=0D + : true));=0D + }=0D +=0D + void=0D + inform_filedescriptor_attribute (access_directions fd_dir)=0D + {=0D +=0D + if (m_attr_name)=0D + switch (fd_dir)=0D + {=0D + case DIRS_READ_WRITE:=0D + inform (DECL_SOURCE_LOCATION (m_callee_fndecl),=0D + "argument %d of %qD must be an open file descriptor, due= to "=0D + "%<__attribute__((%s(%d)))%>",=0D + m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx += 1);=0D + break;=0D + case DIRS_WRITE:=0D + inform (DECL_SOURCE_LOCATION (m_callee_fndecl),=0D + "argument %d of %qD must be a readable file descriptor, = due "=0D + "to %<__attribute__((%s(%d)))%>",=0D + m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx += 1);=0D + break;=0D + case DIRS_READ:=0D + inform (DECL_SOURCE_LOCATION (m_callee_fndecl),=0D + "argument %d of %qD must be a writable file descriptor, = due "=0D + "to %<__attribute__((%s(%d)))%>",=0D + m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx += 1);=0D + break;=0D + }=0D + }=0D +=0D +protected:=0D + tree m_callee_fndecl;=0D + const char *m_attr_name;=0D + /* ARG_IDX is 0-based. */=0D + int m_arg_idx;=0D +};=0D +=0D class fd_leak : public fd_diagnostic=0D {=0D public:=0D @@ -290,18 +368,26 @@ private: diagnostic_event_id_t m_open_event;=0D };=0D =0D -class fd_access_mode_mismatch : public fd_diagnostic=0D +class fd_access_mode_mismatch : public fd_param_diagnostic=0D {=0D public:=0D fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,=0D - enum access_direction fd_dir,=0D - const tree callee_fndecl)=0D - : fd_diagnostic (sm, arg), m_fd_dir (fd_dir),=0D - m_callee_fndecl (callee_fndecl)=0D + enum access_directions fd_dir,=0D + const tree callee_fndecl, const char *attr_name= ,=0D + int arg_idx)=0D + : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx),= =0D + m_fd_dir (fd_dir)=0D =0D {=0D }=0D =0D + fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,=0D + enum access_directions fd_dir,=0D + const tree callee_fndecl)=0D + : fd_param_diagnostic (sm, arg, callee_fndecl), m_fd_dir (fd_dir)=0D + {=0D + }=0D + =0D const char *=0D get_kind () const final override=0D {=0D @@ -317,29 +403,25 @@ public: bool=0D emit (rich_location *rich_loc) final override=0D {=0D + bool warned;=0D switch (m_fd_dir)=0D {=0D - case DIR_READ:=0D - return warning_at (rich_loc, get_controlling_option (),=0D - "%qE on % file descriptor %qE",=0D + case DIRS_READ:=0D + warned =3D warning_at (rich_loc, get_controlling_option (),=0D + "%qE on read-only file descriptor %qE",=0D m_callee_fndecl, m_arg);=0D - case DIR_WRITE:=0D - return warning_at (rich_loc, get_controlling_option (),=0D - "%qE on % file descriptor %qE",=0D + break;=0D + case DIRS_WRITE:=0D + warned =3D warning_at (rich_loc, get_controlling_option (),=0D + "%qE on write-only file descriptor %qE",=0D m_callee_fndecl, m_arg);=0D + break;=0D default:=0D gcc_unreachable ();=0D }=0D - }=0D -=0D - bool=0D - subclass_equal_p (const pending_diagnostic &base_other) const override=0D - {=0D - const fd_access_mode_mismatch &sub_other=0D - =3D (const fd_access_mode_mismatch &)base_other;=0D - return (same_tree_p (m_arg, sub_other.m_arg)=0D - && m_callee_fndecl =3D=3D sub_other.m_callee_fndecl=0D - && m_fd_dir =3D=3D sub_other.m_fd_dir);=0D + if (warned)=0D + inform_filedescriptor_attribute (m_fd_dir);=0D + return warned;=0D }=0D =0D label_text=0D @@ -347,11 +429,11 @@ public: {=0D switch (m_fd_dir)=0D {=0D - case DIR_READ:=0D - return ev.formatted_print ("%qE on % file descriptor %= qE",=0D + case DIRS_READ:=0D + return ev.formatted_print ("%qE on read-only file descriptor %qE",= =0D m_callee_fndecl, m_arg);=0D - case DIR_WRITE:=0D - return ev.formatted_print ("%qE on % file descriptor = %qE",=0D + case DIRS_WRITE:=0D + return ev.formatted_print ("%qE on write-only file descriptor %qE"= ,=0D m_callee_fndecl, m_arg);=0D default:=0D gcc_unreachable ();=0D @@ -359,21 +441,20 @@ public: }=0D =0D private:=0D - enum access_direction m_fd_dir;=0D - const tree m_callee_fndecl;=0D + enum access_directions m_fd_dir;=0D };=0D =0D -class double_close : public fd_diagnostic=0D +class fd_double_close : public fd_diagnostic=0D {=0D public:=0D - double_close (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm,= arg)=0D + fd_double_close (const fd_state_machine &sm, tree arg) : fd_diagnostic (= sm, arg)=0D {=0D }=0D =0D const char *=0D get_kind () const final override=0D {=0D - return "double_close";=0D + return "fd_double_close";=0D }=0D =0D int=0D @@ -418,12 +499,19 @@ private: diagnostic_event_id_t m_first_close_event;=0D };=0D =0D -class fd_use_after_close : public fd_diagnostic=0D +class fd_use_after_close : public fd_param_diagnostic=0D {=0D public:=0D + fd_use_after_close (const fd_state_machine &sm, tree arg,=0D + const tree callee_fndecl, const char *attr_name,=0D + int arg_idx)=0D + : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)=0D + {=0D + }=0D +=0D fd_use_after_close (const fd_state_machine &sm, tree arg,=0D const tree callee_fndecl)=0D - : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl)=0D + : fd_param_diagnostic (sm, arg, callee_fndecl)=0D {=0D }=0D =0D @@ -442,9 +530,13 @@ public: bool=0D emit (rich_location *rich_loc) final override=0D {=0D - return warning_at (rich_loc, get_controlling_option (),=0D + bool warned;=0D + warned =3D warning_at (rich_loc, get_controlling_option (),=0D "%qE on closed file descriptor %qE", m_callee_fndec= l,=0D m_arg);=0D + if (warned)=0D + inform_filedescriptor_attribute (DIRS_READ_WRITE);=0D + return warned;=0D }=0D =0D label_text=0D @@ -466,32 +558,38 @@ public: describe_final_event (const evdesc::final_event &ev) final override=0D {=0D if (m_first_close_event.known_p ())=0D - return ev.formatted_print (=0D - "%qE on closed file descriptor %qE; %qs was at %@", m_callee_fnd= ecl,=0D - m_arg, "close", &m_first_close_event);=0D - else=0D - return ev.formatted_print ("%qE on closed file descriptor %qE",=0D - m_callee_fndecl, m_arg);=0D + return ev.formatted_print (=0D + "%qE on closed file descriptor %qE; %qs was at %@", m_callee_f= ndecl,=0D + m_arg, "close", &m_first_close_event);=0D + else=0D + return ev.formatted_print ("%qE on closed file descriptor %qE",=0D + m_callee_fndecl, m_arg);=0D }=0D =0D private:=0D diagnostic_event_id_t m_first_close_event;=0D - const tree m_callee_fndecl;=0D };=0D =0D -class unchecked_use_of_fd : public fd_diagnostic=0D +class fd_use_without_check : public fd_param_diagnostic=0D {=0D public:=0D - unchecked_use_of_fd (const fd_state_machine &sm, tree arg,=0D - const tree callee_fndecl)=0D - : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl)=0D + fd_use_without_check (const fd_state_machine &sm, tree arg,=0D + const tree callee_fndecl, const char *attr_name,=0D + int arg_idx)=0D + : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)=0D + {=0D + }=0D +=0D + fd_use_without_check (const fd_state_machine &sm, tree arg,=0D + const tree callee_fndecl)=0D + : fd_param_diagnostic (sm, arg, callee_fndecl)=0D {=0D }=0D =0D const char *=0D get_kind () const final override=0D {=0D - return "unchecked_use_of_fd";=0D + return "fd_use_without_check";=0D }=0D =0D int=0D @@ -503,18 +601,13 @@ public: bool=0D emit (rich_location *rich_loc) final override=0D {=0D - return warning_at (rich_loc, get_controlling_option (),=0D - "%qE on possibly invalid file descriptor %qE",=0D - m_callee_fndecl, m_arg);=0D - }=0D -=0D - bool=0D - subclass_equal_p (const pending_diagnostic &base_other) const override=0D - {=0D - const unchecked_use_of_fd &sub_other=0D - =3D (const unchecked_use_of_fd &)base_other;=0D - return (same_tree_p (m_arg, sub_other.m_arg)=0D - && m_callee_fndecl =3D=3D sub_other.m_callee_fndecl);=0D + bool warned;=0D + warned =3D warning_at (rich_loc, get_controlling_option (),=0D + "%qE on possibly invalid file descriptor %qE",=0D + m_callee_fndecl, m_arg);=0D + if (warned)=0D + inform_filedescriptor_attribute (DIRS_READ_WRITE);=0D + return warned;=0D }=0D =0D label_text=0D @@ -541,8 +634,7 @@ public: }=0D =0D private:=0D - diagnostic_event_id_t m_first_open_event;=0D - const tree m_callee_fndecl;=0D + diagnostic_event_id_t m_first_open_event; =0D };=0D =0D fd_state_machine::fd_state_machine (logger *logger)=0D @@ -647,11 +739,117 @@ fd_state_machine::on_stmt (sm_context *sm_ctxt, cons= t supernode *node, on_read (sm_ctxt, node, stmt, call, callee_fndecl);=0D return true;=0D } // "read"=0D +=0D + =0D + {=0D + // Handle __attribute__((fd_arg))=0D +=0D + check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,=0D + "fd_arg", DIRS_READ_WRITE);=0D +=0D + // Handle __attribute__((fd_arg_read))=0D +=0D + check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,=0D + "fd_arg_read", DIRS_READ);=0D +=0D + // Handle __attribute__((fd_arg_write))=0D +=0D + check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,=0D + "fd_arg_write", DIRS_WRITE);=0D + } =0D }=0D =0D return false;=0D }=0D =0D +void=0D +fd_state_machine::check_for_fd_attrs (=0D + sm_context *sm_ctxt, const supernode *node, const gimple *stmt,=0D + const gcall *call, const tree callee_fndecl, const char *attr_name,=0D + access_directions fd_attr_access_dir) const=0D +{=0D +=0D + tree attrs =3D TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl));=0D + attrs =3D lookup_attribute (attr_name, attrs);=0D + if (!attrs)=0D + return;=0D +=0D + if (!TREE_VALUE (attrs))=0D + return;=0D +=0D + auto_bitmap argmap;=0D +=0D + for (tree idx =3D TREE_VALUE (attrs); idx; idx =3D TREE_CHAIN (idx))=0D + {=0D + unsigned int val =3D TREE_INT_CST_LOW (TREE_VALUE (idx)) - 1;=0D + bitmap_set_bit (argmap, val);=0D + }=0D + if (bitmap_empty_p (argmap))=0D + return;=0D +=0D + for (unsigned arg_idx =3D 0; arg_idx < gimple_call_num_args (call); arg_= idx++)=0D + {=0D + tree arg =3D gimple_call_arg (call, arg_idx);=0D + tree diag_arg =3D sm_ctxt->get_diagnostic_tree (arg);=0D + state_t state =3D sm_ctxt->get_state (stmt, arg);=0D + bool bit_set =3D bitmap_bit_p (argmap, arg_idx);=0D + if (TREE_CODE (TREE_TYPE (arg)) !=3D INTEGER_TYPE)=0D + continue;=0D + if (bit_set) // Check if arg_idx is marked by any of the file descri= ptor=0D + // attributes=0D + {=0D +=0D + if (is_closed_fd_p (state))=0D + {=0D +=0D + sm_ctxt->warn (node, stmt, arg,=0D + new fd_use_after_close (*this, diag_arg,=0D + callee_fndecl, attr_n= ame,=0D + arg_idx));=0D + continue;=0D + }=0D +=0D + if (!(is_valid_fd_p (state) || (state =3D=3D m_stop)))=0D + {=0D + if (!is_constant_fd_p (state))=0D + sm_ctxt->warn (node, stmt, arg,=0D + new fd_use_without_check (*this, diag_arg,= =0D + callee_fndecl, att= r_name,=0D + arg_idx));=0D + }=0D +=0D + switch (fd_attr_access_dir)=0D + {=0D + case DIRS_READ_WRITE:=0D + break;=0D + case DIRS_READ:=0D +=0D + if (is_writeonly_fd_p (state))=0D + {=0D + sm_ctxt->warn (=0D + node, stmt, arg,=0D + new fd_access_mode_mismatch (*this, diag_arg, DIRS_W= RITE,=0D + callee_fndecl, attr_nam= e, arg_idx));=0D + }=0D +=0D + break;=0D + case DIRS_WRITE:=0D +=0D + if (is_readonly_fd_p (state))=0D + {=0D + sm_ctxt->warn (=0D + node, stmt, arg,=0D + new fd_access_mode_mismatch (*this, diag_arg, DIRS_R= EAD,=0D + callee_fndecl, attr_nam= e, arg_idx));=0D + }=0D +=0D + break;=0D + }=0D + }=0D + }=0D +}=0D +=0D +=0D void=0D fd_state_machine::on_open (sm_context *sm_ctxt, const supernode *node,=0D const gimple *stmt, const gcall *call) const=0D @@ -706,7 +904,7 @@ fd_state_machine::on_close (sm_context *sm_ctxt, const = supernode *node, =0D if (is_closed_fd_p (state))=0D {=0D - sm_ctxt->warn (node, stmt, arg, new double_close (*this, diag_arg));= =0D + sm_ctxt->warn (node, stmt, arg, new fd_double_close (*this, diag_arg= ));=0D sm_ctxt->set_next_state (stmt, arg, m_stop);=0D }=0D }=0D @@ -715,21 +913,21 @@ fd_state_machine::on_read (sm_context *sm_ctxt, const= supernode *node, const gimple *stmt, const gcall *call,=0D const tree callee_fndecl) const=0D {=0D - check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIR_READ);= =0D + check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_READ);= =0D }=0D void=0D fd_state_machine::on_write (sm_context *sm_ctxt, const supernode *node,=0D const gimple *stmt, const gcall *call,=0D const tree callee_fndecl) const=0D {=0D - check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIR_WRITE);= =0D + check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_WRITE)= ;=0D }=0D =0D void=0D fd_state_machine::check_for_open_fd (=0D sm_context *sm_ctxt, const supernode *node, const gimple *stmt,=0D const gcall *call, const tree callee_fndecl,=0D - enum access_direction callee_fndecl_dir) const=0D + enum access_directions callee_fndecl_dir) const=0D {=0D tree arg =3D gimple_call_arg (call, 0);=0D tree diag_arg =3D sm_ctxt->get_diagnostic_tree (arg);=0D @@ -748,30 +946,32 @@ fd_state_machine::check_for_open_fd ( if (!is_constant_fd_p (state))=0D sm_ctxt->warn (=0D node, stmt, arg,=0D - new unchecked_use_of_fd (*this, diag_arg, callee_fndecl));= =0D + new fd_use_without_check (*this, diag_arg, callee_fndecl))= ;=0D }=0D switch (callee_fndecl_dir)=0D {=0D - case DIR_READ:=0D + case DIRS_READ:=0D if (is_writeonly_fd_p (state))=0D {=0D tree diag_arg =3D sm_ctxt->get_diagnostic_tree (arg);=0D sm_ctxt->warn (node, stmt, arg,=0D new fd_access_mode_mismatch (=0D - *this, diag_arg, DIR_WRITE, callee_fndecl= ));=0D + *this, diag_arg, DIRS_WRITE, callee_fndec= l));=0D }=0D =0D break;=0D - case DIR_WRITE:=0D + case DIRS_WRITE:=0D =0D if (is_readonly_fd_p (state))=0D {=0D tree diag_arg =3D sm_ctxt->get_diagnostic_tree (arg);=0D sm_ctxt->warn (node, stmt, arg,=0D new fd_access_mode_mismatch (=0D - *this, diag_arg, DIR_READ, callee_fndecl)= );=0D + *this, diag_arg, DIRS_READ, callee_fndecl= ));=0D }=0D break;=0D + default:=0D + gcc_unreachable ();=0D }=0D }=0D }=0D diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index c8d96723f4c..e4f1d3542f3 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -173,6 +173,7 @@ static tree handle_objc_nullability_attribute (tree *, = tree, tree, int, bool *); static tree handle_signed_bool_precision_attribute (tree *, tree, tree, in= t, bool *); static tree handle_retain_attribute (tree *, tree, tree, int, bool *); +static tree handle_fd_arg_attribute (tree *, tree, tree, int, bool *); =20 /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -555,6 +556,12 @@ const struct attribute_spec c_common_attribute_table[]= =3D handle_dealloc_attribute, NULL }, { "tainted_args", 0, 0, true, false, false, false, handle_tainted_args_attribute, NULL }, + { "fd_arg", 1, 1, false, true, true, false, + handle_fd_arg_attribute, NULL},=20=20=20=20=20=20 + { "fd_arg_read", 1, 1, false, true, true, false, + handle_fd_arg_attribute, NULL}, + { "fd_arg_write", 1, 1, false, true, true, false, + handle_fd_arg_attribute, NULL},=20=20=20=20=20=20=20=20=20 { NULL, 0, 0, false, false, false, false, NULL, NULL= } }; =20 @@ -4521,6 +4528,30 @@ handle_nonnull_attribute (tree *node, tree name, return NULL_TREE; } =20 +/* Handle the "fd_arg", "fd_arg_read" and "fd_arg_write" attributes */ + +static tree +handle_fd_arg_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree type =3D *node; + if (!args) + { + if (!prototype_p (type)) + { + error ("%qE attribute without arguments on a non-prototype", nam= e); + *no_add_attrs =3D true; + } + return NULL_TREE; + } + + if (positional_argument (*node, name, TREE_VALUE (args), INTEGER_TYPE)) + return NULL_TREE; + + *no_add_attrs =3D true;=20=20 + return NULL_TREE; +} + /* Handle the "nonstring" variable attribute. */ =20 static tree diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index dfbe33ac652..1d08324a70c 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -3007,6 +3007,43 @@ produced by @command{gold}. For other linkers that cannot generate resolution file, explicit @code{externally_visible} attributes are still necessary. =20 +@item fd_arg=20 +@itemx fd_arg (@var{N}) +@cindex @code{fd_arg} function attribute +The @code{fd_arg} attribute may be applied to a function that takes an ope= n=20 +file descriptor at referenced argument @var{N}. + +It indicates that the passed filedescriptor must not have been closed. +Therefore, when the analyzer is enabled with @option{-fanalyzer}, the=20 +analyzer may emit a @option{-Wanalyzer-fd-use-after-close} diagnostic=20 +if it detects a code path in which a function with this attribute is +called with a closed file descriptor. + +The attribute also indicates that the file descriptor must have been check= ed for +validity before usage. Therefore, analyzer may emit +@option{-Wanalyzer-fd-use-without-check} diagnostic if it detects a code p= ath in +which a function with this attribute is called with a file descriptor that= has +not been checked for validity. + +@item fd_arg_read +@itemx fd_arg_read (@var{N}) +@cindex @code{fd_arg_read} function attribute +The @code{fd_arg_read} is identical to @code{fd_arg}, but with the additio= nal +requirement that it might read from the file descriptor, and thus, the file +descriptor must not have been opened as write-only. + +The analyzer may emit a @option{-Wanalyzer-access-mode-mismatch} +diagnostic if it detects a code path in which a function with this +attribute is called on a file descriptor opened with @code{O_WRONLY}. + +@item fd_arg_write +@itemx fd_arg_write (@var{N}) +@cindex @code{fd_arg_write} function attribute +The @code{fd_arg_write} is identical to @code{fd_arg_read} except that the +analyzer may emit a @option{-Wanalyzer-access-mode-mismatch} diagnostic if= =20 +it detects a code path in which a function with this attribute is called o= n a=20 +file descriptor opened with @code{O_RDONLY}. + @item flatten @cindex @code{flatten} function attribute Generally, inlining into a function is limited. For a function marked with diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d5ff1018372..c5b97e65197 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -9843,7 +9843,13 @@ This warning requires @option{-fanalyzer}, which ena= bles it; use to disable it. =20 This diagnostic warns for paths through code in which a=20 -@code{read} on a write-only file descriptor is attempted, or vice versa +@code{read} on a write-only file descriptor is attempted, or vice versa. + +This diagnostic also warns for code paths in a which a function with attri= bute +@code{fd_arg_read (N)} is called with a file descriptor opened with +@code{O_WRONLY} at referenced argument @code{N} or a function with attribu= te +@code{fd_arg_write (N)} is called with a file descriptor opened with +@code{O_RDONLY} at referenced argument @var{N}. =20 @item -Wno-analyzer-fd-double-close @opindex Wanalyzer-fd-double-close @@ -9875,6 +9881,11 @@ to disable it. This diagnostic warns for paths through code in which a=20 read or write is called on a closed file descriptor. =20 +This diagnostic also warns for paths through code in which +a function with attribute @code{fd_arg (N)} or @code{fd_arg_read (N)} +or @code{fd_arg_write (N)} is called with a closed file descriptor at +referenced argument @code{N}. + @item -Wno-analyzer-fd-use-without-check @opindex Wanalyzer-fd-use-without-check @opindex Wno-analyzer-fd-use-without-check @@ -9885,6 +9896,11 @@ to disable it. This diagnostic warns for paths through code in which a=20 file descriptor is used without being checked for validity. =20 +This diagnostic also warns for paths through code in which +a function with attribute @code{fd_arg (N)} or @code{fd_arg_read (N)} +or @code{fd_arg_write (N)} is called with a file descriptor, at referenced +argument @code{N}, without being checked for validity. + @item -Wno-analyzer-file-leak @opindex Wanalyzer-file-leak @opindex Wno-analyzer-file-leak diff --git a/gcc/testsuite/c-c++-common/attr-fd.c b/gcc/testsuite/c-c++-com= mon/attr-fd.c new file mode 100644 index 00000000000..e4bb4ed0374 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-fd.c @@ -0,0 +1,18 @@ +=0D +int not_a_fn __attribute__ ((fd_arg(1))); /* { dg-warning "'fd_arg' attrib= ute only applies to function types" } */=0D +=0D +void f (char *p) __attribute__ ((fd_arg(1))); /* { dg-warning "'fd_arg' at= tribute argument value '1' refers to parameter type 'char ?\\\*'" } */=0D +=0D +=0D +int not_a_fn_b __attribute__ ((fd_arg_read(1))); /* { dg-warning "'fd_arg_= read' attribute only applies to function types" } */=0D +=0D +void g (char *p) __attribute__ ((fd_arg_read(1))); /* { dg-warning "'fd_ar= g_read' attribute argument value '1' refers to parameter type 'char ?\\\*'"= } */=0D +=0D +=0D +int not_a_fn_c __attribute__ ((fd_arg_write(1))); /* { dg-warning "'fd_arg= _write' attribute only applies to function types" } */=0D +=0D +void f (char *p) __attribute__ ((fd_arg_write(1))); /* { dg-warning "'fd_a= rg_write' attribute argument value '1' refers to parameter type 'char ?\\\*= '" } */=0D +=0D +=0D +void fn_a (int fd) __attribute__ ((fd_arg(0))); /* { dg-warning "'fd_arg' = attribute argument value '0' does not refer to a function parameter" } */=0D +void fd_a_1 (int fd) __attribute__ ((fd_arg("notint"))); /* { dg-warning "= 'fd_arg' attribute argument has type ('char\\\[7\\\]'|'const char\\\*')" } = */=0D diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-4.c b/gcc/testsuite/gcc.dg/an= alyzer/fd-4.c index fcfa6168efa..41263468a6c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-4.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-4.c @@ -17,9 +17,9 @@ test_1 (const char *path, void *buf) if (fd >=3D 0) /* { dg-message "assuming 'fd' is a valid file descript= or \\(>=3D 0\\)" "event1" } */=0D /* { dg-message "following 'true' branch \\(when 'fd >=3D 0'\\)..." "e= vent2" { target *-*-* } .-1 } */=0D {=0D - write (fd, buf, 1); /* { dg-warning "'write' on 'read-only' file d= escriptor 'fd'" "warning" } */=0D + write (fd, buf, 1); /* { dg-warning "'write' on read-only file des= criptor 'fd'" "warning" } */=0D /* { dg-message "\\(4\\) ...to here" "event1" { target *-*-* } .-1= } */=0D - /* { dg-message "\\(5\\) 'write' on 'read-only' file descriptor 'f= d'" "event2" { target *-*-* } .-2 } */=0D + /* { dg-message "\\(5\\) 'write' on read-only file descriptor 'fd'= " "event2" { target *-*-* } .-2 } */=0D close (fd);=0D }=0D }=0D @@ -31,9 +31,9 @@ test_2 (const char *path, void *buf) if (fd >=3D 0) /* { dg-message "assuming 'fd' is a valid file descript= or \\(>=3D 0\\)" "event1" } */=0D /* { dg-message "following 'true' branch \\(when 'fd >=3D 0'\\)..." "e= vent2" { target *-*-* } .-1 } */=0D {=0D - read (fd, buf, 1); /* { dg-warning "'read' on 'write-only' file de= scriptor 'fd'" "warning" } */=0D + read (fd, buf, 1); /* { dg-warning "'read' on write-only file desc= riptor 'fd'" "warning" } */=0D /* { dg-message "\\(4\\) ...to here" "event1" { target *-*-* } .-1= } */=0D - /* { dg-message "\\(5\\) 'read' on 'write-only' file descriptor 'f= d'" "event2" { target *-*-* } .-2 } */=0D + /* { dg-message "\\(5\\) 'read' on write-only file descriptor 'fd'= " "event2" { target *-*-* } .-2 } */=0D close (fd);=0D }=0D }=0D diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-5.c b/gcc/testsuite/gcc.dg/an= alyzer/fd-5.c new file mode 100644 index 00000000000..8f29c11b3e8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/fd-5.c @@ -0,0 +1,53 @@ +int open(const char *, int mode);=0D +void close(int fd);=0D +int write (int fd, void *buf, int nbytes);=0D +int read (int fd, void *buf, int nbytes);=0D +=0D +#define O_RDONLY 0=0D +#define O_WRONLY 1=0D +#define O_RDWR 2=0D +=0D +void f (int fd) __attribute__((fd_arg(1))); /* { dg-message "argument 1 of= 'f' must be an open file descriptor, due to '__attribute__\\(\\(fd_arg\\(1= \\)\\)\\)'" } */=0D +=0D +void=0D +test_1 (const char *path)=0D +{=0D + int fd =3D open (path, O_RDWR);=0D + close(fd);=0D + f(fd); /* { dg-warning "'f' on closed file descriptor 'fd'" } */=0D + /* { dg-message "\\(3\\) 'f' on closed file descriptor 'fd'; 'close'= was at \\(2\\)" "" { target *-*-* } .-1 } */=0D +}=0D +=0D +void g (int fd) __attribute__((fd_arg_read(1))); /* { dg-message "argument= 1 of 'g' must be a readable file descriptor, due to '__attribute__\\(\\(fd= _arg_read\\(1\\)\\)\\)'" } */=0D +=0D +void=0D +test_2 (const char *path)=0D +{=0D + int fd =3D open (path, O_WRONLY);=0D + if (fd !=3D -1)=0D + {=0D + g (fd); /* { dg-warning "'g' on write-only file descriptor 'fd'" } */= =0D + }=0D + close (fd);=0D +}=0D +=0D +void h (int fd) __attribute__((fd_arg_write(1))); /* { dg-message "argumen= t 1 of 'h' must be a writable file descriptor, due to '__attribute__\\(\\(f= d_arg_write\\(1\\)\\)\\)'" } */=0D +void=0D +test_3 (const char *path)=0D +{=0D + int fd =3D open (path, O_RDONLY);=0D + if (fd !=3D -1)=0D + {=0D + h (fd); /* { dg-warning "'h' on read-only file descriptor 'fd'" } */=0D + }=0D + close(fd);=0D +}=0D +=0D +void ff (int fd) __attribute__((fd_arg(1))); /* { dg-message "argument 1 o= f 'ff' must be an open file descriptor, due to '__attribute__\\(\\(fd_arg\\= (1\\)\\)\\)'" } */=0D +=0D +void test_4 (const char *path)=0D +{=0D + int fd =3D open (path, O_RDWR);=0D + ff (fd); /* { dg-warning "'ff' on possibly invalid file descriptor 'fd'"= } */=0D + close(fd);=0D +} \ No newline at end of file --=20 2.25.1