Message ID | 7pq3onsr-r66r-s43o-7p4-9n5o5672q1q@fhfr.qr |
---|---|
State | Committed |
Commit | 1374d4b963a6ac2e0ec1645c09e5162e68b009d6 |
Headers |
Return-Path: <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B8D143858034 for <patchwork@sourceware.org>; Mon, 17 Jan 2022 14:32:30 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B8D143858034 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1642429950; bh=95nsGlIFz38sOMfXnTZUEQnIGtm41wHZGR8z2OueGaE=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=A22ki9LGFzT2ZbaZixhwm3T/i6lM0frhz5OjhOSUAsRXmPtZsfVudz5JIhvJ+tPc8 98GUeNkvtWeovV2OI9ifokD3BqOn6RIQyDLT78jgBQ9DJENFxejEPoB0m/Y7y8PSzF dTA96J0OQ81ctx61dJqYRpn01jDehJMn3bI3BXZc= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by sourceware.org (Postfix) with ESMTPS id 1B6043858416 for <gcc-patches@gcc.gnu.org>; Mon, 17 Jan 2022 14:32:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 1B6043858416 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id EE852212B6 for <gcc-patches@gcc.gnu.org>; Mon, 17 Jan 2022 14:32:00 +0000 (UTC) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id DB62D13C0E for <gcc-patches@gcc.gnu.org>; Mon, 17 Jan 2022 14:32:00 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 3JhlNOB95WH3GgAAMHmgww (envelope-from <rguenther@suse.de>) for <gcc-patches@gcc.gnu.org>; Mon, 17 Jan 2022 14:32:00 +0000 Date: Mon, 17 Jan 2022 15:32:00 +0100 (CET) To: gcc-patches@gcc.gnu.org Subject: [PATCH] middle-end/101292 - invalid memory access with warning control Message-ID: <7pq3onsr-r66r-s43o-7p4-9n5o5672q1q@fhfr.qr> MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII 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, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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 <gcc-patches.gcc.gnu.org> List-Unsubscribe: <https://gcc.gnu.org/mailman/options/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe> List-Archive: <https://gcc.gnu.org/pipermail/gcc-patches/> List-Post: <mailto:gcc-patches@gcc.gnu.org> List-Help: <mailto:gcc-patches-request@gcc.gnu.org?subject=help> List-Subscribe: <https://gcc.gnu.org/mailman/listinfo/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe> From: Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> Reply-To: Richard Biener <rguenther@suse.de> Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> |
Series |
middle-end/101292 - invalid memory access with warning control
|
|
Commit Message
Richard Biener
Jan. 17, 2022, 2:32 p.m. UTC
The warning control falls into the C++ trap of using a reference to old hashtable contents for a put operation which can end up re-allocating that before reading from the old freed referenced to source. Fixed by introducing a temporary. Bootstrap & regtest running on x86_64-unknown-linux-gnu. 2022-01-17 Richard Biener <rguenther@suse.de> PR middle-end/101292 * diagnostic-spec.c (copy_warning): Make sure to not reference old hashtable content on possible resize. * warning-control.cc (copy_warning): Likewise. --- gcc/diagnostic-spec.c | 5 ++++- gcc/warning-control.cc | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-)
Comments
On 1/17/22 07:32, Richard Biener via Gcc-patches wrote: > The warning control falls into the C++ trap of using a reference > to old hashtable contents for a put operation which can end up > re-allocating that before reading from the old freed referenced to > source. Fixed by introducing a temporary. I think a better place to fix this and avoid the gotcha once and for all is in the GCC hash_map: C++ containers are expected to handle the insertion of own elements gracefully. Martin > > Bootstrap & regtest running on x86_64-unknown-linux-gnu. > > 2022-01-17 Richard Biener <rguenther@suse.de> > > PR middle-end/101292 > * diagnostic-spec.c (copy_warning): Make sure to not > reference old hashtable content on possible resize. > * warning-control.cc (copy_warning): Likewise. > --- > gcc/diagnostic-spec.c | 5 ++++- > gcc/warning-control.cc | 3 ++- > 2 files changed, 6 insertions(+), 2 deletions(-) > > diff --git a/gcc/diagnostic-spec.c b/gcc/diagnostic-spec.c > index a8af229d677..4341ccfaae9 100644 > --- a/gcc/diagnostic-spec.c > +++ b/gcc/diagnostic-spec.c > @@ -195,7 +195,10 @@ copy_warning (location_t to, location_t from) > else > { > if (from_spec) > - nowarn_map->put (to, *from_spec); > + { > + nowarn_spec_t tem = *from_spec; > + nowarn_map->put (to, tem); > + } > else > nowarn_map->remove (to); > } > diff --git a/gcc/warning-control.cc b/gcc/warning-control.cc > index f9808bf4392..fa39ecab421 100644 > --- a/gcc/warning-control.cc > +++ b/gcc/warning-control.cc > @@ -206,7 +206,8 @@ void copy_warning (ToType to, FromType from) > gcc_assert (supp); > > gcc_checking_assert (nowarn_map); > - nowarn_map->put (to_loc, *from_spec); > + nowarn_spec_t tem = *from_spec; > + nowarn_map->put (to_loc, tem); > } > else > {
On Mon, 17 Jan 2022, Martin Sebor wrote: > On 1/17/22 07:32, Richard Biener via Gcc-patches wrote: > > The warning control falls into the C++ trap of using a reference > > to old hashtable contents for a put operation which can end up > > re-allocating that before reading from the old freed referenced to > > source. Fixed by introducing a temporary. > > I think a better place to fix this and avoid the gotcha once and > for all is in the GCC hash_map: C++ containers are expected to > handle the insertion of own elements gracefully. I don't think that's reasonably possible if you consider T *a = map.get (X); T *b = map.get (Y); map.put (Z, *a); map.put (W, *b); the only way to "fix" it would be to change the API to not return by reference for get, remove get_or_insert (or change its API to also require passing the new value). Note the above shows that making 'put' take the value by value instead of by reference doesn't work either. IMHO the issue is that C++ doesn't make it obvious that 'put' gets a pointer to the old element (stupid references). Richard. > Martin > > > > > Bootstrap & regtest running on x86_64-unknown-linux-gnu. > > > > 2022-01-17 Richard Biener <rguenther@suse.de> > > > > PR middle-end/101292 > > * diagnostic-spec.c (copy_warning): Make sure to not > > reference old hashtable content on possible resize. > > * warning-control.cc (copy_warning): Likewise. > > --- > > gcc/diagnostic-spec.c | 5 ++++- > > gcc/warning-control.cc | 3 ++- > > 2 files changed, 6 insertions(+), 2 deletions(-) > > > > diff --git a/gcc/diagnostic-spec.c b/gcc/diagnostic-spec.c > > index a8af229d677..4341ccfaae9 100644 > > --- a/gcc/diagnostic-spec.c > > +++ b/gcc/diagnostic-spec.c > > @@ -195,7 +195,10 @@ copy_warning (location_t to, location_t from) > > else > > { > > if (from_spec) > > - nowarn_map->put (to, *from_spec); > > + { > > + nowarn_spec_t tem = *from_spec; > > + nowarn_map->put (to, tem); > > + } > > else > > nowarn_map->remove (to); > > } > > diff --git a/gcc/warning-control.cc b/gcc/warning-control.cc > > index f9808bf4392..fa39ecab421 100644 > > --- a/gcc/warning-control.cc > > +++ b/gcc/warning-control.cc > > @@ -206,7 +206,8 @@ void copy_warning (ToType to, FromType from) > > gcc_assert (supp); > > > > gcc_checking_assert (nowarn_map); > > - nowarn_map->put (to_loc, *from_spec); > > + nowarn_spec_t tem = *from_spec; > > + nowarn_map->put (to_loc, tem); > > } > > else > > { > >
On 1/18/22 01:36, Richard Biener wrote: > On Mon, 17 Jan 2022, Martin Sebor wrote: > >> On 1/17/22 07:32, Richard Biener via Gcc-patches wrote: >>> The warning control falls into the C++ trap of using a reference >>> to old hashtable contents for a put operation which can end up >>> re-allocating that before reading from the old freed referenced to >>> source. Fixed by introducing a temporary. >> >> I think a better place to fix this and avoid the gotcha once and >> for all is in the GCC hash_map: C++ containers are expected to >> handle the insertion of own elements gracefully. > > I don't think that's reasonably possible if you consider > > T *a = map.get (X); > T *b = map.get (Y); > map.put (Z, *a); > map.put (W, *b); This case is up to the caller to handle, the same as anything else involving pointers or references into reallocated storage (it's no different in C than it is in C++). The specific case I'm referring to is passing a pointer or reference to a single element in a container to the first modifying call on the container. > > the only way to "fix" it would be to change the API to not > return by reference for get, remove get_or_insert (or change > its API to also require passing the new value). No, the fix is to have the modifying function create a copy of the element being inserted before reallocating the container. > > Note the above shows that making 'put' take the value by > value instead of by reference doesn't work either. > > IMHO the issue is that C++ doesn't make it obvious that 'put' > gets a pointer to the old element (stupid references). The problem isn't specific to references, it can come up with pointers just as easily. Pointers might just make it more obvious. Martin > > Richard. > >> Martin >> >>> >>> Bootstrap & regtest running on x86_64-unknown-linux-gnu. >>> >>> 2022-01-17 Richard Biener <rguenther@suse.de> >>> >>> PR middle-end/101292 >>> * diagnostic-spec.c (copy_warning): Make sure to not >>> reference old hashtable content on possible resize. >>> * warning-control.cc (copy_warning): Likewise. >>> --- >>> gcc/diagnostic-spec.c | 5 ++++- >>> gcc/warning-control.cc | 3 ++- >>> 2 files changed, 6 insertions(+), 2 deletions(-) >>> >>> diff --git a/gcc/diagnostic-spec.c b/gcc/diagnostic-spec.c >>> index a8af229d677..4341ccfaae9 100644 >>> --- a/gcc/diagnostic-spec.c >>> +++ b/gcc/diagnostic-spec.c >>> @@ -195,7 +195,10 @@ copy_warning (location_t to, location_t from) >>> else >>> { >>> if (from_spec) >>> - nowarn_map->put (to, *from_spec); >>> + { >>> + nowarn_spec_t tem = *from_spec; >>> + nowarn_map->put (to, tem); >>> + } >>> else >>> nowarn_map->remove (to); >>> } >>> diff --git a/gcc/warning-control.cc b/gcc/warning-control.cc >>> index f9808bf4392..fa39ecab421 100644 >>> --- a/gcc/warning-control.cc >>> +++ b/gcc/warning-control.cc >>> @@ -206,7 +206,8 @@ void copy_warning (ToType to, FromType from) >>> gcc_assert (supp); >>> >>> gcc_checking_assert (nowarn_map); >>> - nowarn_map->put (to_loc, *from_spec); >>> + nowarn_spec_t tem = *from_spec; >>> + nowarn_map->put (to_loc, tem); >>> } >>> else >>> { >> >> >
On Tue, 18 Jan 2022, Martin Sebor wrote: > On 1/18/22 01:36, Richard Biener wrote: > > On Mon, 17 Jan 2022, Martin Sebor wrote: > > > >> On 1/17/22 07:32, Richard Biener via Gcc-patches wrote: > >>> The warning control falls into the C++ trap of using a reference > >>> to old hashtable contents for a put operation which can end up > >>> re-allocating that before reading from the old freed referenced to > >>> source. Fixed by introducing a temporary. > >> > >> I think a better place to fix this and avoid the gotcha once and > >> for all is in the GCC hash_map: C++ containers are expected to > >> handle the insertion of own elements gracefully. > > > > I don't think that's reasonably possible if you consider > > > > T *a = map.get (X); > > T *b = map.get (Y); > > map.put (Z, *a); > > map.put (W, *b); > > This case is up to the caller to handle, the same as anything else > involving pointers or references into reallocated storage (it's no > different in C than it is in C++). > > The specific case I'm referring to is passing a pointer or reference > to a single element in a container to the first modifying call on > the container. Huh, that's a quite special case I'm not sure "fixing" will avoid the mistake. > > > > the only way to "fix" it would be to change the API to not > > return by reference for get, remove get_or_insert (or change > > its API to also require passing the new value). > > No, the fix is to have the modifying function create a copy of > the element being inserted before reallocating the container. Sure, that's possible I guess. Richard.
diff --git a/gcc/diagnostic-spec.c b/gcc/diagnostic-spec.c index a8af229d677..4341ccfaae9 100644 --- a/gcc/diagnostic-spec.c +++ b/gcc/diagnostic-spec.c @@ -195,7 +195,10 @@ copy_warning (location_t to, location_t from) else { if (from_spec) - nowarn_map->put (to, *from_spec); + { + nowarn_spec_t tem = *from_spec; + nowarn_map->put (to, tem); + } else nowarn_map->remove (to); } diff --git a/gcc/warning-control.cc b/gcc/warning-control.cc index f9808bf4392..fa39ecab421 100644 --- a/gcc/warning-control.cc +++ b/gcc/warning-control.cc @@ -206,7 +206,8 @@ void copy_warning (ToType to, FromType from) gcc_assert (supp); gcc_checking_assert (nowarn_map); - nowarn_map->put (to_loc, *from_spec); + nowarn_spec_t tem = *from_spec; + nowarn_map->put (to_loc, tem); } else {