From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id D83423858C52 for ; Sat, 12 Nov 2022 03:32:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D83423858C52 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668223933; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6KFWtqaPYRCh3Fjm81OxEoh37dTZgIh+roNFz5+7cKM=; b=FbKo+JlU8QYlhjz846Y4h0lNLZZl0nWHHnGXTd7GJcMHpBNue7wL2v3tglmcqT+v3pfnz1 EeRrNs1O1AKJNkg+EmNDutYmA9MhCvtQNN90aaEcn8wcwQTPW8XCPZ5lcAg1ZRpUo+HP4R zlLDGhCK3fdpNQj9qoLyR7cDirvPhD8= Received: from mail-qv1-f71.google.com (mail-qv1-f71.google.com [209.85.219.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-79-_gE82bQJMS2OxuapX8_kEg-1; Fri, 11 Nov 2022 22:32:11 -0500 X-MC-Unique: _gE82bQJMS2OxuapX8_kEg-1 Received: by mail-qv1-f71.google.com with SMTP id nh17-20020a056214391100b004bb6c16bd4dso4937213qvb.17 for ; Fri, 11 Nov 2022 19:32:11 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=6KFWtqaPYRCh3Fjm81OxEoh37dTZgIh+roNFz5+7cKM=; b=kOif3G7WsWV0SoLa2HAIPT4r75yw98b4laCzmktE9yiL1/hLEUzRz6O07tEhTINNi2 8bu7I9jOwA7gciUEIa5YN9PEYgDc/K8yjP8LWRNdlIqrt8ACnH5pAeI7R6SucY41uPgl cForAJYYmGiuI4TP3+E+HIjFnrJ32slkFrXEtvrn6lxDL1ZnNHYwIb+mpQSN3JgVeAWu UnY2Tlsp49S3S1imMj6xWVeNfFuG+idQZlTLl1CNq9Z+ECpZ99+DsVXURSiAVZGMAUUQ E+gF4hllJcq8bXqbPuOgR5dPCCHTSCA8V/2Bs5p0BW6WpfvCtbVnFNUu+9uO3rPeatCF XFuA== X-Gm-Message-State: ANoB5pncOuFrKHE1X95GpKtD6XVk7AiDhnrboXDWzPhEcs/U5apa5JXI 9B8UYGY31zIIjqg0e38xOxElIcHD8t3WDRrkITYETI25N8zsH9eIEMgYSpJJAx3n6OHLcvmorMd SIYYBaOWJ67naj/ft83Ri65Kku5+xzDYvWAn+sNq0Gwdyjcd+WpTbRHvW2iAsDkfkFRjjgA== X-Received: by 2002:a0c:f849:0:b0:4bb:699e:4cec with SMTP id g9-20020a0cf849000000b004bb699e4cecmr4775033qvo.6.1668223930406; Fri, 11 Nov 2022 19:32:10 -0800 (PST) X-Google-Smtp-Source: AA0mqf63xHmM4C7cDPz1Gelbe+7CyCF5UTOdbPIDEqZghsaPrtttQvySN2R5/3GdAYA2d3+6w8lvLg== X-Received: by 2002:a0c:f849:0:b0:4bb:699e:4cec with SMTP id g9-20020a0cf849000000b004bb699e4cecmr4774985qvo.6.1668223928550; Fri, 11 Nov 2022 19:32:08 -0800 (PST) Received: from t14s.localdomain (c-73-69-212-193.hsd1.nh.comcast.net. [73.69.212.193]) by smtp.gmail.com with ESMTPSA id fp1-20020a05622a508100b0039ee562799csm2228713qtb.59.2022.11.11.19.32.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Nov 2022 19:32:08 -0800 (PST) Message-ID: <8bd04399163661fde948dc052f21ee567b7b9f46.camel@redhat.com> Subject: Re: [PATCH v2] c, analyzer: support named constants in analyzer [PR106302] From: David Malcolm To: gcc-patches@gcc.gnu.org, Joseph Myers Cc: Marek Polacek Date: Fri, 11 Nov 2022 22:32:07 -0500 In-Reply-To: <20221112032310.2723361-1-dmalcolm@redhat.com> References: <20221112032310.2723361-1-dmalcolm@redhat.com> User-Agent: Evolution 3.44.4 (3.44.4-1.fc36) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00,BODY_8BITS,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Fri, 2022-11-11 at 22:23 -0500, David Malcolm wrote: > Changes since v1: ported the doc changes from texinfo to sphinx >=20 > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. >=20 > Are the C frontend parts OK for trunk?=C2=A0 (I can self-approve the > analyzer parts) ...and FWIW, the followup patch that uses this to add checking of sockets to -fanalyzer is here: [PATCH v2] analyzer: add warnings relating to sockets [PR106140] https://gcc.gnu.org/pipermail/gcc-patches/2022-November/605836.html Thanks Dave >=20 > Thanks > Dave >=20 >=20 > The analyzer's file-descriptor state machine tracks the access mode > of > opened files, so that it can emit -Wanalyzer-fd-access-mode-mismatch. >=20 > To do this, its symbolic execution needs to "know" the values of the > constants "O_RDONLY", "O_WRONLY", and "O_ACCMODE".=C2=A0 Currently > analyzer/sm-fd.cc simply uses these values directly from the build- > time > header files, but these are the values on the host, not those from > the > target, which could be different (PR analyzer/106302). >=20 > In an earlier discussion of this issue: > =C2=A0 https://gcc.gnu.org/pipermail/gcc/2022-June/238954.html > we talked about adding a target hook for this. >=20 > However, I've also been experimenting with extending the fd state > machine to track sockets (PR analyzer/106140).=C2=A0 For this, it's usefu= l > to > "know" the values of the constants "SOCK_STREAM" and "SOCK_DGRAM". > Unfortunately, these seem to have many arbitrary differences from > target > to target. >=20 > For example: Linux/glibc general has SOCK_STREAM =3D=3D 1, SOCK_DGRAM =3D= =3D > 2, > as does AIX, but annoyingly, e.g. Linux on MIPS has them the other > way > around. >=20 > It seems to me that as the analyzer grows more ambitious modeling of > the > behavior of APIs (perhaps via plugins) it's more likely that the > analyzer will need to know the values of named constants, which might > not even exist on the host. >=20 > For example, at LPC it was suggested to me that -fanalyzer could > check > rules about memory management inside the Linux kernel (probably via a > plugin), but doing so involves a bunch of GFP_* flags (see PR > 107472). >=20 > So rather than trying to capture all this knowledge in a target hook, > this patch attempts to get at named constant values from the user's > source code. >=20 > The patch adds an interface for frontends to call into the analyzer > as > the translation unit finishes.=C2=A0 The analyzer can then call back into > the > frontend to ask about the values of the named constants it cares > about > whilst the frontend's data structures are still around. >=20 > The patch implements this for the C frontend, which looks up the > names > by looking for named CONST_DECLs (which handles enum values).=C2=A0 > Failing > that, it attempts to look up the values of macros but only the > simplest > cases are supported (a non-traditional macro with a single CPP_NUMBER > token).=C2=A0 It does this by building a buffer containing the macro > definition and rerunning a lexer on it. >=20 > The analyzer gracefully handles the cases where named values aren't > found (such as anything more complicated than described above). >=20 > The patch ports the analyzer to use this mechanism for "O_RDONLY", > "O_WRONLY", and "O_ACCMODE".=C2=A0 I have successfully tested my socket > patch > to also use this for "SOCK_STREAM" and "SOCK_DGRAM", so the technique > seems to work. >=20 > gcc/ChangeLog: > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0PR analyzer/106302 > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* Makefile.in (ANALYZER_O= BJS): Add analyzer/analyzer- > language.o. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(GTFILES): Add analyzer/a= nalyzer-language.cc. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* doc/gccint/debugging-th= e-analyzer.rst: Document > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0__analyzer_dump_named_con= stant. >=20 > gcc/analyzer/ChangeLog: > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0PR analyzer/106302 > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* analyzer-language.cc: N= ew file. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* analyzer-language.h: Ne= w file. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* analyzer.h (get_stashed= _constant_by_name): New decl. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(log_stashed_constants): = New decl. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* engine.cc (impl_run_che= ckers): Call log_stashed_constants. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* region-model-impl-calls= .cc > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(region_model::impl_call_= analyzer_dump_named_constant): New. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* region-model.cc (region= _model::on_stmt_pre): Handle > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0__analyzer_dump_named_con= stant. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* region-model.h > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(region_model::impl_call_= analyzer_dump_named_constant): New > decl. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* sm-fd.cc (fd_state_mach= ine::m_O_ACCMODE): New. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(fd_state_machine::m_O_RD= ONLY): New. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(fd_state_machine::m_O_WR= ONLY): New. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(fd_state_machine::fd_sta= te_machine): Initialize the new > fields. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(fd_state_machine::get_ac= cess_mode_from_flag): Use the new > fields, > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0rather than using the hos= t values. >=20 > gcc/c/ChangeLog: > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0PR analyzer/106302 > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* c-parser.cc: Include "a= nalyzer/analyzer-language.h" and > "toplev.h". > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(class ana::c_translation= _unit): New. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(c_parser_translation_uni= t): Call > ana::on_finish_translation_unit. >=20 > gcc/testsuite/ChangeLog: > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/analyze= r-decls.h > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(__analyzer_dump_named_co= nstant): New decl. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/fd-4.c = (void): Likewise. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(O_ACCMODE): Define. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/fd-acce= ss-mode-enum.c: New test, based on . > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/fd-5.c:= ...this.=C2=A0 Rename to... > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/fd-acce= ss-mode-macros.c: ...this. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(O_ACCMODE): Define. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/fd-acce= ss-mode-target-headers.c: New test, > also > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0based on fd-5.c. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(test_sm_fd_constants): N= ew. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/fd-dup-= 1.c (O_ACCMODE): Define. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/named-c= onstants-via-enum.c: New test. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/named-c= onstants-via-macros-2.c: New test. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* gcc.dg/analyzer/named-c= onstants-via-macros.c: New test. >=20 > Signed-off-by: David Malcolm > --- > =C2=A0gcc/Makefile.in=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0=C2=A0 2 + > =C2=A0gcc/analyzer/analyzer-language.cc=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 | 110 > ++++++++++++++++++ > =C2=A0gcc/analyzer/analyzer-language.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0 48 ++++++++ > =C2=A0gcc/analyzer/analyzer.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 |=C2=A0=C2=A0 3 + > =C2=A0gcc/analyzer/engine.cc=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 |=C2=A0=C2=A0 1 + > =C2=A0gcc/analyzer/region-model-impl-calls.cc=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 |=C2=A0 28 +++++ > =C2=A0gcc/analyzer/region-model.cc=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0=C2= =A0 4 + > =C2=A0gcc/analyzer/region-model.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2= =A0=C2=A0 2 + > =C2=A0gcc/analyzer/sm-fd.cc=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0 30 +++-- > =C2=A0gcc/c/c-parser.cc=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0 91 +++++++++++++++ > =C2=A0gcc/doc/gccint/debugging-the-analyzer.rst=C2=A0=C2=A0=C2=A0=C2=A0 |= =C2=A0 17 +++ > =C2=A0.../gcc.dg/analyzer/analyzer-decls.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0=C2=A0 3 + > =C2=A0gcc/testsuite/gcc.dg/analyzer/fd-4.c=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0=C2=A0 1 + > =C2=A0.../gcc.dg/analyzer/fd-access-mode-enum.c=C2=A0=C2=A0=C2=A0=C2=A0 |= =C2=A0 60 ++++++++++ > =C2=A0.../{fd-5.c =3D> fd-access-mode-macros.c}=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 |=C2=A0=C2=A0 1 + > =C2=A0.../analyzer/fd-access-mode-target-headers.c=C2=A0 |=C2=A0 56 +++++= ++++ > =C2=A0gcc/testsuite/gcc.dg/analyzer/fd-dup-1.c=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 |=C2=A0=C2=A0 1 + > =C2=A0.../analyzer/named-constants-via-enum.c=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 |=C2=A0 20 ++++ > =C2=A0.../analyzer/named-constants-via-macros-2.c=C2=A0=C2=A0 |=C2=A0 15 = +++ > =C2=A0.../analyzer/named-constants-via-macros.c=C2=A0=C2=A0=C2=A0=C2=A0 |= =C2=A0 19 +++ > =C2=A020 files changed, 502 insertions(+), 10 deletions(-) > =C2=A0create mode 100644 gcc/analyzer/analyzer-language.cc > =C2=A0create mode 100644 gcc/analyzer/analyzer-language.h > =C2=A0create mode 100644 gcc/testsuite/gcc.dg/analyzer/fd-access-mode- > enum.c > =C2=A0rename gcc/testsuite/gcc.dg/analyzer/{fd-5.c =3D> fd-access-mode- > macros.c} (98%) > =C2=A0create mode 100644 gcc/testsuite/gcc.dg/analyzer/fd-access-mode- > target-headers.c > =C2=A0create mode 100644 gcc/testsuite/gcc.dg/analyzer/named-constants- > via-enum.c > =C2=A0create mode 100644 gcc/testsuite/gcc.dg/analyzer/named-constants- > via-macros-2.c > =C2=A0create mode 100644 gcc/testsuite/gcc.dg/analyzer/named-constants- > via-macros.c >=20 > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index 246a85a1677..684caedc2df 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1236,6 +1236,7 @@ C_COMMON_OBJS =3D c-family/c-common.o c-family/c- > cppbuiltin.o c-family/c-dump.o \ > =C2=A0ANALYZER_OBJS =3D \ > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0analyzer/analysis-plan.o = \ > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0analyzer/analyzer.o \ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0analyzer/analyzer-language.o \ > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0analyzer/analyzer-logging= .o \ > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0analyzer/analyzer-pass.o = \ > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0analyzer/analyzer-selftes= ts.o \ > @@ -2709,6 +2710,7 @@ GTFILES =3D $(CPPLIB_H) $(srcdir)/input.h > $(srcdir)/coretypes.h \ > =C2=A0=C2=A0 $(srcdir)/internal-fn.h \ > =C2=A0=C2=A0 $(srcdir)/calls.cc \ > =C2=A0=C2=A0 $(srcdir)/omp-general.h \ > +=C2=A0 $(srcdir)/analyzer/analyzer-language.cc \ > =C2=A0=C2=A0 @all_gtfiles@ > =C2=A0 > =C2=A0# Compute the list of GT header files from the corresponding C > sources, > diff --git a/gcc/analyzer/analyzer-language.cc > b/gcc/analyzer/analyzer-language.cc > new file mode 100644 > index 00000000000..ba4352b729a > --- /dev/null > +++ b/gcc/analyzer/analyzer-language.cc > @@ -0,0 +1,110 @@ > +/* Interface between analyzer and frontends. > +=C2=A0=C2=A0 Copyright (C) 2022 Free Software Foundation, Inc. > +=C2=A0=C2=A0 Contributed by David Malcolm . > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify it > +under the terms of the GNU General Public License as published by > +the Free Software Foundation; either version 3, or (at your option) > +any later version. > + > +GCC is distributed in the hope that it will be useful, but > +WITHOUT ANY WARRANTY; without even the implied warranty of > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 See the GNU > +General Public License for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3.=C2=A0 If not see > +.=C2=A0 */ > + > +#include "config.h" > +#define INCLUDE_MEMORY > +#include "system.h" > +#include "coretypes.h" > +#include "tree.h" > +#include "stringpool.h" > +#include "analyzer/analyzer.h" > +#include "analyzer/analyzer-language.h" > +#include "analyzer/analyzer-logging.h" > + > +/* Map from identifier to INTEGER_CST.=C2=A0 */ > +static GTY (()) hash_map *analyzer_stashed_constants; > + > +#if ENABLE_ANALYZER > + > +namespace ana { > + > +/* Call into TU to try to find a value for NAME. > +=C2=A0=C2=A0 If found, stash its value within analyzer_stashed_constants= .=C2=A0 */ > + > +static void > +maybe_stash_named_constant (const translation_unit &tu, const char > *name) > +{ > +=C2=A0 if (!analyzer_stashed_constants) > +=C2=A0=C2=A0=C2=A0 analyzer_stashed_constants =3D hash_map::= create_ggc > (); > + > +=C2=A0 tree id =3D get_identifier (name); > +=C2=A0 if (tree t =3D tu.lookup_constant_by_id (id)) > +=C2=A0=C2=A0=C2=A0 { > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 gcc_assert (TREE_CODE (t) =3D=3D INTEGER_= CST); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 analyzer_stashed_constants->put (id, t); > +=C2=A0=C2=A0=C2=A0 } > +} > + > +/* Hook for frontend to call into analyzer when TU finishes. > +=C2=A0=C2=A0 This exists so that the analyzer can stash named constant v= alues > from > +=C2=A0=C2=A0 header files (e.g. macros and enums) for later use when mod= eling > the > +=C2=A0=C2=A0 behaviors of APIs. > + > +=C2=A0=C2=A0 By doing it this way, the analyzer can use the precise valu= es for > those > +=C2=A0=C2=A0 constants from the user's headers, rather than attempting t= o > model them > +=C2=A0=C2=A0 as properties of the target.=C2=A0 */ > + > +void > +on_finish_translation_unit (const translation_unit &tu) > +{ > +=C2=A0 /* Bail if the analyzer isn't enabled.=C2=A0 */ > +=C2=A0 if (!flag_analyzer) > +=C2=A0=C2=A0=C2=A0 return; > + > +=C2=A0 /* Stash named constants for use by sm-fd.cc=C2=A0 */ > +=C2=A0 maybe_stash_named_constant (tu, "O_ACCMODE"); > +=C2=A0 maybe_stash_named_constant (tu, "O_RDONLY"); > +=C2=A0 maybe_stash_named_constant (tu, "O_WRONLY"); > +} > + > +/* Lookup NAME in the named constants stashed when the frontend TU > finished. > +=C2=A0=C2=A0 Return either an INTEGER_CST, or NULL_TREE.=C2=A0 */ > + > +tree > +get_stashed_constant_by_name (const char *name) > +{ > +=C2=A0 if (!analyzer_stashed_constants) > +=C2=A0=C2=A0=C2=A0 return NULL_TREE; > +=C2=A0 tree id =3D get_identifier (name); > +=C2=A0 if (tree *slot =3D analyzer_stashed_constants->get (id)) > +=C2=A0=C2=A0=C2=A0 { > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 gcc_assert (TREE_CODE (*slot) =3D=3D INTE= GER_CST); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return *slot; > +=C2=A0=C2=A0=C2=A0 } > +=C2=A0 return NULL_TREE; > +} > + > +/* Log all stashed named constants to LOGGER.=C2=A0 */ > + > +void > +log_stashed_constants (logger *logger) > +{ > +=C2=A0 gcc_assert (logger); > +=C2=A0 LOG_SCOPE (logger); > +=C2=A0 if (analyzer_stashed_constants) > +=C2=A0=C2=A0=C2=A0 for (auto iter : *analyzer_stashed_constants) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 logger->log ("%qE: %qE", iter.first, iter= .second); > +} > + > +} // namespace ana > + > +#endif /* #if ENABLE_ANALYZER */ > + > +#include "gt-analyzer-language.h" > diff --git a/gcc/analyzer/analyzer-language.h > b/gcc/analyzer/analyzer-language.h > new file mode 100644 > index 00000000000..33c4dd60623 > --- /dev/null > +++ b/gcc/analyzer/analyzer-language.h > @@ -0,0 +1,48 @@ > +/* Interface between analyzer and frontends. > +=C2=A0=C2=A0 Copyright (C) 2022 Free Software Foundation, Inc. > +=C2=A0=C2=A0 Contributed by David Malcolm . > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify it > +under the terms of the GNU General Public License as published by > +the Free Software Foundation; either version 3, or (at your option) > +any later version. > + > +GCC is distributed in the hope that it will be useful, but > +WITHOUT ANY WARRANTY; without even the implied warranty of > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 See the GNU > +General Public License for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3.=C2=A0 If not see > +.=C2=A0 */ > + > +#ifndef GCC_ANALYZER_LANGUAGE_H > +#define GCC_ANALYZER_LANGUAGE_H > + > +#if ENABLE_ANALYZER > + > +namespace ana { > + > +/* Abstract base class for representing a specific TU > +=C2=A0=C2=A0 to the analyzer.=C2=A0 */ > + > +class translation_unit > +{ > + public: > +=C2=A0 /* Attempt to look up an=C2=A0 value for identifier ID (e.g. in t= he > headers that > +=C2=A0=C2=A0=C2=A0=C2=A0 have been seen).=C2=A0 If it is defined and an = integer (e.g. either > as a > +=C2=A0=C2=A0=C2=A0=C2=A0 macro or enum), return the INTEGER_CST value, o= therwise return > NULL.=C2=A0 */ > +=C2=A0 virtual tree lookup_constant_by_id (tree id) const =3D 0; > +}; > + > +/* Analyzer hook for frontends to call at the end of the TU.=C2=A0 */ > + > +void on_finish_translation_unit (const translation_unit &tu); > + > +} // namespace ana > + > +#endif /* #if ENABLE_ANALYZER */ > + > +#endif /* GCC_ANALYZER_LANGUAGE_H */ > diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h > index c0041c35d1a..9cf8d98fabe 100644 > --- a/gcc/analyzer/analyzer.h > +++ b/gcc/analyzer/analyzer.h > @@ -311,6 +311,9 @@ public: > =C2=A0=C2=A0 virtual bool terminate_path_p () const =3D 0; > =C2=A0}; > =C2=A0 > +extern tree get_stashed_constant_by_name (const char *name); > +extern void log_stashed_constants (logger *logger); > + > =C2=A0} // namespace ana > =C2=A0 > =C2=A0extern bool is_special_named_call_p (const gcall *call, const char > *funcname, > diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc > index d0595ef0d07..891be7c5c90 100644 > --- a/gcc/analyzer/engine.cc > +++ b/gcc/analyzer/engine.cc > @@ -6010,6 +6010,7 @@ impl_run_checkers (logger *logger) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 logger->log ("BITS_BIG_ENDIAN: %i", = BITS_BIG_ENDIAN ? 1 : 0); > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 logger->log ("BYTES_BIG_ENDIAN: %i",= BYTES_BIG_ENDIAN ? 1 : > 0); > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 logger->log ("WORDS_BIG_ENDIAN: %i",= WORDS_BIG_ENDIAN ? 1 : > 0); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 log_stashed_constants (logger); > =C2=A0=C2=A0=C2=A0=C2=A0 } > =C2=A0 > =C2=A0=C2=A0 /* If using LTO, ensure that the cgraph nodes have function > bodies.=C2=A0 */ > diff --git a/gcc/analyzer/region-model-impl-calls.cc > b/gcc/analyzer/region-model-impl-calls.cc > index 9ef31f6ab05..a7134ed90bb 100644 > --- a/gcc/analyzer/region-model-impl-calls.cc > +++ b/gcc/analyzer/region-model-impl-calls.cc > @@ -352,6 +352,34 @@ region_model::impl_call_analyzer_dump_escaped > (const gcall *call) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 pp_formatted_text (&pp)); > =C2=A0} > =C2=A0 > +/* Handle a call to "__analyzer_dump_named_constant". > + > +=C2=A0=C2=A0 Look up the given name, and emit a warning describing the > +=C2=A0=C2=A0 state of the corresponding stashed value. > + > +=C2=A0=C2=A0 This is for use when debugging, and for DejaGnu tests.=C2= =A0 */ > + > +void > +region_model:: > +impl_call_analyzer_dump_named_constant (const gcall *call, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0region_model_context *ctxt) > +{ > +=C2=A0 call_details cd (call, this, ctxt); > +=C2=A0 const char *name =3D cd.get_arg_string_literal (0); > +=C2=A0 if (!name) > +=C2=A0=C2=A0=C2=A0 { > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 error_at (call->location, "cannot determi= ne name"); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; > +=C2=A0=C2=A0=C2=A0 } > +=C2=A0 tree value =3D get_stashed_constant_by_name (name); > +=C2=A0 if (value) > +=C2=A0=C2=A0=C2=A0 warning_at (call->location, 0, "named constant %qs ha= s value > %qE", > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0name, value); > +=C2=A0 else > +=C2=A0=C2=A0=C2=A0 warning_at (call->location, 0, "named constant %qs ha= s unknown > value", > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0name); > +} > + > =C2=A0/* Handle a call to "__analyzer_eval" by evaluating the input > =C2=A0=C2=A0=C2=A0 and dumping as a dummy warning, so that test cases can= use > =C2=A0=C2=A0=C2=A0 dg-warning to validate the result (and so unexpected w= arnings > will > diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region- > model.cc > index b91434d7db4..5bae3cf5cd4 100644 > --- a/gcc/analyzer/region-model.cc > +++ b/gcc/analyzer/region-model.cc > @@ -1229,6 +1229,10 @@ region_model::on_stmt_pre (const gimple *stmt, > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 impl_call_analyzer= _dump_capacity (call, ctxt); > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (is_special_named= _call_p (call, > "__analyzer_dump_escaped", 0)) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 impl_call_analyzer= _dump_escaped (call); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (is_special_named_call= _p (call, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 > "__analyzer_dump_named_constant", > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 1)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 impl_call_analyzer_dump= _named_constant (call, ctxt); > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (is_special_named= _call_p (call, > "__analyzer_dump_path", 0)) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 { > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 /* Han= dle the builtin "__analyzer_dump_path" by queuing a > diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region- > model.h > index 50790596726..bd81e6b6b9d 100644 > --- a/gcc/analyzer/region-model.h > +++ b/gcc/analyzer/region-model.h > @@ -344,6 +344,8 @@ class region_model > =C2=A0=C2=A0 void impl_call_analyzer_dump_capacity (const gcall *call, > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 region_model_context *ctxt); > =C2=A0=C2=A0 void impl_call_analyzer_dump_escaped (const gcall *call); > +=C2=A0 void impl_call_analyzer_dump_named_constant (const gcall *call, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 region_model_context > *ctxt); > =C2=A0=C2=A0 void impl_call_analyzer_eval (const gcall *call, > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0region_model_context *ctxt); > =C2=A0=C2=A0 void impl_call_analyzer_get_unknown_ptr (const call_details = &cd); > diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc > index da0e92b5113..370115d56bf 100644 > --- a/gcc/analyzer/sm-fd.cc > +++ b/gcc/analyzer/sm-fd.cc > @@ -159,6 +159,11 @@ public: > =C2=A0=C2=A0 /* State for a file descriptor that we do not want to track > anymore . */ > =C2=A0=C2=A0 state_t m_stop; > =C2=A0 > +=C2=A0 /* Stashed constant values from the frontend.=C2=A0 These could b= e > NULL.=C2=A0 */ > +=C2=A0 tree m_O_ACCMODE; > +=C2=A0 tree m_O_RDONLY; > +=C2=A0 tree m_O_WRONLY; > + > =C2=A0private: > =C2=A0=C2=A0 void on_open (sm_context *sm_ctxt, const supernode *node, co= nst > gimple *stmt, > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0const gcall *call) const; > @@ -686,7 +691,10 @@ fd_state_machine::fd_state_machine (logger > *logger) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 m_valid_write_only (add_state ("fd-v= alid-write-only")), > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 m_invalid (add_state ("fd-invalid"))= , > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 m_closed (add_state ("fd-closed")), > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 m_stop (add_state ("fd-stop")) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 m_stop (add_state ("fd-stop")), > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 m_O_ACCMODE (get_stashed_constant_by_name= ("O_ACCMODE")), > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 m_O_RDONLY (get_stashed_constant_by_name = ("O_RDONLY")), > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 m_O_WRONLY (get_stashed_constant_by_name = ("O_WRONLY")) > =C2=A0{ > =C2=A0} > =C2=A0 > @@ -709,16 +717,18 @@ fd_state_machine::is_valid_fd_p (state_t s) > const > =C2=A0enum access_mode > =C2=A0fd_state_machine::get_access_mode_from_flag (int flag) const > =C2=A0{ > -=C2=A0 /* FIXME: this code assumes the access modes on the host and > -=C2=A0=C2=A0=C2=A0=C2=A0 target are the same, which in practice might no= t be the case.=C2=A0 > */ > - > -=C2=A0 if ((flag & O_ACCMODE) =3D=3D O_RDONLY) > -=C2=A0=C2=A0=C2=A0 { > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return READ_ONLY; > -=C2=A0=C2=A0=C2=A0 } > -=C2=A0 else if ((flag & O_ACCMODE) =3D=3D O_WRONLY) > +=C2=A0 if (m_O_ACCMODE && TREE_CODE (m_O_ACCMODE) =3D=3D INTEGER_CST) > =C2=A0=C2=A0=C2=A0=C2=A0 { > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return WRITE_ONLY; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 const unsigned HOST_WIDE_INT mask_val =3D= TREE_INT_CST_LOW > (m_O_ACCMODE); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 const unsigned HOST_WIDE_INT masked_flag = =3D flag & mask_val; > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (m_O_RDONLY && TREE_CODE (m_O_RDONLY) = =3D=3D INTEGER_CST) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (masked_flag =3D=3D TREE_IN= T_CST_LOW (m_O_RDONLY)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return READ_ONLY; > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (m_O_WRONLY && TREE_CODE (m_O_WRONLY) = =3D=3D INTEGER_CST) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (masked_flag =3D=3D TREE_IN= T_CST_LOW (m_O_WRONLY)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return WRITE_ONLY; > =C2=A0=C2=A0=C2=A0=C2=A0 } > =C2=A0=C2=A0 return READ_WRITE; > =C2=A0} > diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc > index d70697b1d63..efe19fbe70b 100644 > --- a/gcc/c/c-parser.cc > +++ b/gcc/c/c-parser.cc > @@ -72,6 +72,8 @@ along with GCC; see the file COPYING3.=C2=A0 If not see > =C2=A0#include "memmodel.h" > =C2=A0#include "c-family/known-headers.h" > =C2=A0#include "bitmap.h" > +#include "analyzer/analyzer-language.h" > +#include "toplev.h" > =C2=A0 > =C2=A0/* We need to walk over decls with incomplete struct/union/enum > types > =C2=A0=C2=A0=C2=A0 after parsing the whole translation unit. > @@ -1662,6 +1664,87 @@ static bool > c_parser_objc_diagnose_bad_element_prefix > =C2=A0=C2=A0 (c_parser *, struct c_declspecs *); > =C2=A0static location_t c_parser_parse_rtl_body (c_parser *, char *); > =C2=A0 > +#if ENABLE_ANALYZER > + > +namespace ana { > + > +/* Concrete implementation of ana::translation_unit for the C > frontend.=C2=A0 */ > + > +class c_translation_unit : public translation_unit > +{ > +public: > +=C2=A0 /* Implementation of translation_unit::lookup_constant_by_id for > use by the > +=C2=A0=C2=A0=C2=A0=C2=A0 analyzer to look up named constants in the user= 's source code.=C2=A0 > */ > +=C2=A0 tree lookup_constant_by_id (tree id) const final override > +=C2=A0 { > +=C2=A0=C2=A0=C2=A0 /* Consider decls.=C2=A0 */ > +=C2=A0=C2=A0=C2=A0 if (tree decl =3D lookup_name (id)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (TREE_CODE (decl) =3D=3D CONST_DECL) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (tree value =3D DECL_INITIA= L (decl)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (TREE_CODE (value) = =3D=3D INTEGER_CST) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return valu= e; > + > +=C2=A0=C2=A0=C2=A0 /* Consider macros.=C2=A0 */ > +=C2=A0=C2=A0=C2=A0 cpp_hashnode *hashnode =3D C_CPP_HASHNODE (id); > +=C2=A0=C2=A0=C2=A0 if (cpp_macro_p (hashnode)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (tree value =3D consider_macro (hashno= de->value.macro)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return value; > + > +=C2=A0=C2=A0=C2=A0 return NULL_TREE; > +=C2=A0 } > + > +private: > +=C2=A0 /* Attempt to get an INTEGER_CST from MACRO. > +=C2=A0=C2=A0=C2=A0=C2=A0 Only handle the simplest cases: where MACRO's d= efinition is a > single > +=C2=A0=C2=A0=C2=A0=C2=A0 token containing a number, by lexing the number= again. > +=C2=A0=C2=A0=C2=A0=C2=A0 This will handle e.g. > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #define NAME 42 > +=C2=A0=C2=A0=C2=A0=C2=A0 and other bases but not negative numbers, paren= theses or e.g. > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #define NAME 1 << 7 > +=C2=A0=C2=A0=C2=A0=C2=A0 as doing so would require a parser.=C2=A0 */ > +=C2=A0 tree consider_macro (cpp_macro *macro) const > +=C2=A0 { > +=C2=A0=C2=A0=C2=A0 if (macro->paramc > 0) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NULL_TREE; > +=C2=A0=C2=A0=C2=A0 if (macro->kind =3D=3D cmk_traditional) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NULL_TREE; > +=C2=A0=C2=A0=C2=A0 if (macro->count !=3D 1) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NULL_TREE; > +=C2=A0=C2=A0=C2=A0 const cpp_token &tok =3D macro->exp.tokens[0]; > +=C2=A0=C2=A0=C2=A0 if (tok.type !=3D CPP_NUMBER) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NULL_TREE; > + > +=C2=A0=C2=A0=C2=A0 cpp_reader *old_parse_in =3D parse_in; > +=C2=A0=C2=A0=C2=A0 parse_in =3D cpp_create_reader (c_dialect_cxx () ? CL= K_GNUCXX: > CLK_GNUC89, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ident_hash, line_table); > + > +=C2=A0=C2=A0=C2=A0 pretty_printer pp; > +=C2=A0=C2=A0=C2=A0 pp_string (&pp, (const char *)tok.val.str.text); > +=C2=A0=C2=A0=C2=A0 pp_newline (&pp); > +=C2=A0=C2=A0=C2=A0 cpp_push_buffer (parse_in, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (const unsigned char *)pp_format= ted_text (&pp), > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 strlen (pp_formatted_text (&pp))= , > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0); > + > +=C2=A0=C2=A0=C2=A0 tree value; > +=C2=A0=C2=A0=C2=A0 location_t loc; > +=C2=A0=C2=A0=C2=A0 unsigned char cpp_flags; > +=C2=A0=C2=A0=C2=A0 c_lex_with_flags (&value, &loc, &cpp_flags, 0); > + > +=C2=A0=C2=A0=C2=A0 cpp_destroy (parse_in); > +=C2=A0=C2=A0=C2=A0 parse_in =3D old_parse_in; > + > +=C2=A0=C2=A0=C2=A0 if (value && TREE_CODE (value) =3D=3D INTEGER_CST) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return value; > + > +=C2=A0=C2=A0=C2=A0 return NULL_TREE; > +=C2=A0 } > +}; > + > +} // namespace ana > + > +#endif /* #if ENABLE_ANALYZER */ > + > =C2=A0/* Parse a translation unit (C90 6.7, C99 6.9, C11 6.9). > =C2=A0 > =C2=A0=C2=A0=C2=A0 translation-unit: > @@ -1722,6 +1805,14 @@ c_parser_translation_unit (c_parser *parser) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 "#pragma omp begin assumes", "#pragma omp end > assumes"); > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 current_omp_begin_assumes =3D 0; > =C2=A0=C2=A0=C2=A0=C2=A0 } > + > +#if ENABLE_ANALYZER > +=C2=A0 if (flag_analyzer) > +=C2=A0=C2=A0=C2=A0 { > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ana::c_translation_unit tu; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ana::on_finish_translation_unit (tu); > +=C2=A0=C2=A0=C2=A0 } > +#endif > =C2=A0} > =C2=A0 > =C2=A0/* Parse an external declaration (C90 6.7, C99 6.9, C11 6.9). > diff --git a/gcc/doc/gccint/debugging-the-analyzer.rst > b/gcc/doc/gccint/debugging-the-analyzer.rst > index 4a09b39e166..099acf295b9 100644 > --- a/gcc/doc/gccint/debugging-the-analyzer.rst > +++ b/gcc/doc/gccint/debugging-the-analyzer.rst > @@ -90,6 +90,23 @@ With a non-zero argument > =C2=A0 > =C2=A0it will also dump all of the states within the 'processed' nodes. > =C2=A0 > +The builtin ``__analyzer_dump_named_constant`` will emit a warning > +during analysis describing what is known about the value of a given > +named constant, for parts of the analyzer that interact with target > +headers. > + > +For example: > + > +.. code-block:: c > + > +=C2=A0=C2=A0 __analyzer_dump_named_constant ("O_RDONLY"); > + > +might emit the warning: > + > +.. code-block:: > + > +=C2=A0=C2=A0 warning: named constant 'O_RDONLY' has value '1' > + > =C2=A0.. code-block:: c++ > =C2=A0 > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 __analyzer_dump_region_model (); > diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h > b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h > index 4478d740b58..d9a32ed9370 100644 > --- a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h > +++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h > @@ -31,6 +31,9 @@ extern void __analyzer_dump_escaped (void); > =C2=A0=C2=A0=C2=A0 will also dump all of the states within those nodes.= =C2=A0 */ > =C2=A0extern void __analyzer_dump_exploded_nodes (int); > =C2=A0 > +/* Emit a warning describing what is known about the value of NAME.=C2= =A0 > */ > +extern void __analyzer_dump_named_constant (const char *name); > + > =C2=A0/* Emit a placeholder "note" diagnostic with a path to this call > site, > =C2=A0=C2=A0=C2=A0 if the analyzer finds a feasible path to it.=C2=A0 */ > =C2=A0extern void __analyzer_dump_path (void); > diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-4.c > b/gcc/testsuite/gcc.dg/analyzer/fd-4.c > index 842a26b4364..994bad84342 100644 > --- a/gcc/testsuite/gcc.dg/analyzer/fd-4.c > +++ b/gcc/testsuite/gcc.dg/analyzer/fd-4.c > @@ -8,6 +8,7 @@ void close(int fd); > =C2=A0int write (int fd, void *buf, int nbytes); > =C2=A0int read (int fd, void *buf, int nbytes); > =C2=A0 > +#define O_ACCMODE 0xf > =C2=A0#define O_RDONLY 0 > =C2=A0#define O_WRONLY 1 > =C2=A0#define O_RDWR 2 > diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-enum.c > b/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-enum.c > new file mode 100644 > index 00000000000..5226569c437 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-enum.c > @@ -0,0 +1,60 @@ > +int open(const char *, int mode); > +void close(int fd); > +int write (int fd, void *buf, int nbytes); > +int read (int fd, void *buf, int nbytes); > + > +/* Example of these flags as an enum, and with > +=C2=A0=C2=A0 non-standard values for them.=C2=A0 */ > + > +enum { > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 O_RDONLY=C2=A0 =3D 0x10, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 O_WRONLY=C2=A0 =3D 0x20, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 O_RDWR=C2=A0=C2=A0=C2=A0 =3D 0x40, > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 O_ACCMODE =3D 0xf0 > +}; > + > +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\\)\\)\\)'" } */ > + > +void > +test_1 (const char *path) > +{ > +=C2=A0=C2=A0=C2=A0 int fd =3D open (path, O_RDWR); > +=C2=A0=C2=A0=C2=A0 close(fd); > +=C2=A0=C2=A0=C2=A0 f(fd); /* { dg-warning "'f' on closed file descriptor= 'fd'" } */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 /* { dg-message "\\(3\\) 'f' on closed fi= le descriptor 'fd'; > 'close' was at \\(2\\)" "" { target *-*-* } .-1 } */ > +} > + > +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\\)\\)\\)'" } */ > + > +void > +test_2 (const char *path) > +{ > +=C2=A0 int fd =3D open (path, O_WRONLY); > +=C2=A0 if (fd !=3D -1) > +=C2=A0 { > +=C2=A0=C2=A0=C2=A0 g (fd); /* { dg-warning "'g' on write-only file descr= iptor 'fd'" > } */ > +=C2=A0 } > +=C2=A0 close (fd); > +} > + > +void h (int fd) __attribute__((fd_arg_write(1))); /* { dg-message > "argument 1 of 'h' must be a writable file descriptor, due to > '__attribute__\\(\\(fd_arg_write\\(1\\)\\)\\)'" } */ > +void > +test_3 (const char *path) > +{ > +=C2=A0 int fd =3D open (path, O_RDONLY); > +=C2=A0 if (fd !=3D -1) > +=C2=A0 { > +=C2=A0=C2=A0=C2=A0 h (fd); /* { dg-warning "'h' on read-only file descri= ptor 'fd'" > } */ > +=C2=A0 } > +=C2=A0 close(fd); > +} > + > +void ff (int fd) __attribute__((fd_arg(1))); /* { dg-message > "argument 1 of 'ff' must be an open file descriptor, due to > '__attribute__\\(\\(fd_arg\\(1\\)\\)\\)'" } */ > + > +void test_4 (const char *path) > +{ > +=C2=A0 int fd =3D open (path, O_RDWR); > +=C2=A0 ff (fd); /* { dg-warning "'ff' on possibly invalid file descripto= r > 'fd'" } */ > +=C2=A0 close(fd); > +} > diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-5.c > b/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-macros.c > similarity index 98% > rename from gcc/testsuite/gcc.dg/analyzer/fd-5.c > rename to gcc/testsuite/gcc.dg/analyzer/fd-access-mode-macros.c > index c18b2adcbe5..f9a6931a5db 100644 > --- a/gcc/testsuite/gcc.dg/analyzer/fd-5.c > +++ b/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-macros.c > @@ -6,6 +6,7 @@ int read (int fd, void *buf, int nbytes); > =C2=A0#define O_RDONLY 0 > =C2=A0#define O_WRONLY 1 > =C2=A0#define O_RDWR 2 > +#define O_ACCMODE 0x3 > =C2=A0 > =C2=A0void 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\\)\\)\\)'" } */ > =C2=A0 > diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-target- > headers.c b/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-target- > headers.c > new file mode 100644 > index 00000000000..b76eb667d50 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-target-headers.c > @@ -0,0 +1,56 @@ > +#include > +#include > +#include > +#include "analyzer-decls.h" > + > +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\\)\\)\\)'" } */ > + > +void > +test_1 (const char *path) > +{ > +=C2=A0=C2=A0=C2=A0 int fd =3D open (path, O_RDWR); > +=C2=A0=C2=A0=C2=A0 close(fd); > +=C2=A0=C2=A0=C2=A0 f(fd); /* { dg-warning "'f' on closed file descriptor= 'fd'" } */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 /* { dg-message "\\(3\\) 'f' on closed fi= le descriptor 'fd'; > 'close' was at \\(2\\)" "" { target *-*-* } .-1 } */ > +} > + > +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\\)\\)\\)'" } */ > + > +void > +test_2 (const char *path) > +{ > +=C2=A0 int fd =3D open (path, O_WRONLY); > +=C2=A0 if (fd !=3D -1) > +=C2=A0 { > +=C2=A0=C2=A0=C2=A0 g (fd); /* { dg-warning "'g' on write-only file descr= iptor 'fd'" > } */ > +=C2=A0 } > +=C2=A0 close (fd); > +} > + > +void h (int fd) __attribute__((fd_arg_write(1))); /* { dg-message > "argument 1 of 'h' must be a writable file descriptor, due to > '__attribute__\\(\\(fd_arg_write\\(1\\)\\)\\)'" } */ > +void > +test_3 (const char *path) > +{ > +=C2=A0 int fd =3D open (path, O_RDONLY); > +=C2=A0 if (fd !=3D -1) > +=C2=A0 { > +=C2=A0=C2=A0=C2=A0 h (fd); /* { dg-warning "'h' on read-only file descri= ptor 'fd'" > } */ > +=C2=A0 } > +=C2=A0 close(fd); > +} > + > +void ff (int fd) __attribute__((fd_arg(1))); /* { dg-message > "argument 1 of 'ff' must be an open file descriptor, due to > '__attribute__\\(\\(fd_arg\\(1\\)\\)\\)'" } */ > + > +void test_4 (const char *path) > +{ > +=C2=A0 int fd =3D open (path, O_RDWR); > +=C2=A0 ff (fd); /* { dg-warning "'ff' on possibly invalid file descripto= r > 'fd'" } */ > +=C2=A0 close(fd); > +} > + > +void test_sm_fd_constants (void) > +{ > +=C2=A0 __analyzer_dump_named_constant ("O_ACCMODE"); /* { dg-warning > "named constant 'O_ACCMODE' has value '\[0-9\]+'" } */ > +=C2=A0 __analyzer_dump_named_constant ("O_RDONLY"); /* { dg-warning > "named constant 'O_RDONLY' has value '\[0-9\]+'" } */ > +=C2=A0 __analyzer_dump_named_constant ("O_WRONLY"); /* { dg-warning > "named constant 'O_WRONLY' has value '\[0-9\]+'" } */ > +} > diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-dup-1.c > b/gcc/testsuite/gcc.dg/analyzer/fd-dup-1.c > index b4f43e7f0ef..bb58e9d9d5e 100644 > --- a/gcc/testsuite/gcc.dg/analyzer/fd-dup-1.c > +++ b/gcc/testsuite/gcc.dg/analyzer/fd-dup-1.c > @@ -8,6 +8,7 @@ int read (int fd, void *buf, int nbytes); > =C2=A0#define O_RDONLY 0 > =C2=A0#define O_WRONLY 1 > =C2=A0#define O_RDWR 2 > +#define O_ACCMODE 3 > =C2=A0 > =C2=A0void test_1 (const char *path) > =C2=A0{ > diff --git a/gcc/testsuite/gcc.dg/analyzer/named-constants-via-enum.c > b/gcc/testsuite/gcc.dg/analyzer/named-constants-via-enum.c > new file mode 100644 > index 00000000000..e6b77b8dd18 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/analyzer/named-constants-via-enum.c > @@ -0,0 +1,20 @@ > +#include "analyzer-decls.h" > + > +/* Various constants used by the fd state machine.=C2=A0 */ > +enum { > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 O_ACCMODE =3D 42, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 O_RDONLY=C2=A0 =3D 0x1, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 O_WRONLY=C2=A0 =3D 010 > +}; > + > +void test_sm_fd_constants (void) > +{ > +=C2=A0 __analyzer_dump_named_constant ("O_ACCMODE"); /* { dg-warning > "named constant 'O_ACCMODE' has value '42'" } */ > +=C2=A0 __analyzer_dump_named_constant ("O_RDONLY"); /* { dg-warning > "named constant 'O_RDONLY' has value '1'" } */ > +=C2=A0 __analyzer_dump_named_constant ("O_WRONLY"); /* { dg-warning > "named constant 'O_WRONLY' has value '8'" } */ > +} > + > +void test_unknown (void) > +{ > +=C2=A0 __analyzer_dump_named_constant ("UNKNOWN"); /* { dg-warning "name= d > constant 'UNKNOWN' has unknown value" } */ > +} > diff --git a/gcc/testsuite/gcc.dg/analyzer/named-constants-via- > macros-2.c b/gcc/testsuite/gcc.dg/analyzer/named-constants-via- > macros-2.c > new file mode 100644 > index 00000000000..9c019e7c5ef > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/analyzer/named-constants-via-macros-2.c > @@ -0,0 +1,15 @@ > +#include "analyzer-decls.h" > + > +/* Various constants used by the fd state machine, as macros > +=C2=A0=C2=A0 that can't be handled.=C2=A0 */ > + > +#define O_ACCMODE ( > +#define O_RDONLY=C2=A0 "foo" > +#define O_WRONLY=C2=A0 int > + > +void test_sm_fd_constants (void) > +{ > +=C2=A0 __analyzer_dump_named_constant ("O_ACCMODE"); /* { dg-warning > "named constant 'O_ACCMODE' has unknown value" } */ > +=C2=A0 __analyzer_dump_named_constant ("O_RDONLY"); /* { dg-warning > "named constant 'O_RDONLY' has unknown value" } */ > +=C2=A0 __analyzer_dump_named_constant ("O_WRONLY"); /* { dg-warning > "named constant 'O_WRONLY' has unknown value" } */ > +} > diff --git a/gcc/testsuite/gcc.dg/analyzer/named-constants-via- > macros.c b/gcc/testsuite/gcc.dg/analyzer/named-constants-via-macros.c > new file mode 100644 > index 00000000000..2022f98e5b6 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/analyzer/named-constants-via-macros.c > @@ -0,0 +1,19 @@ > +#include "analyzer-decls.h" > + > +/* Various constants used by the fd state machine.=C2=A0 */ > + > +#define O_ACCMODE 42 > +#define O_RDONLY=C2=A0 0x1 > +#define O_WRONLY=C2=A0 010 > + > +void test_sm_fd_constants (void) > +{ > +=C2=A0 __analyzer_dump_named_constant ("O_ACCMODE"); /* { dg-warning > "named constant 'O_ACCMODE' has value '42'" } */ > +=C2=A0 __analyzer_dump_named_constant ("O_RDONLY"); /* { dg-warning > "named constant 'O_RDONLY' has value '1'" } */ > +=C2=A0 __analyzer_dump_named_constant ("O_WRONLY"); /* { dg-warning > "named constant 'O_WRONLY' has value '8'" } */ > +} > + > +void test_unknown (void) > +{ > +=C2=A0 __analyzer_dump_named_constant ("UNKNOWN"); /* { dg-warning "name= d > constant 'UNKNOWN' has unknown value" } */ > +}