From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7862) id 80A1B385800B; Mon, 10 Oct 2022 10:13:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 80A1B385800B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1665396833; bh=v+tO9AaCYXrS7tHKJTaMxpDYnSC3LU+uTxthO98g0xU=; h=From:To:Subject:Date:From; b=IIL+nwQXL+piWD12XyAH3ISoyz8j2OBLQ5u3lERT7ATRZB67iGkS3wJuMOGdNOgj6 6PLfU74788Kn0kjKGsGorZI4YWu7pDuToTfprKi7GHt73ZFf7inezRh01SvFHckQBd hE5UmDyXNdiw4AupkJAkrvlPn7YasEThbbqKHfuc= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Bruno Larsen To: gdb-cvs@sourceware.org Subject: [binutils-gdb] Introduce frame_info_ptr smart pointer class X-Act-Checkin: binutils-gdb X-Git-Author: Tom Tromey X-Git-Refname: refs/heads/master X-Git-Oldrev: a0cbd6505e9590baddd27d2ce603103d6e77421a X-Git-Newrev: ba380b3e5162e89c4c81a73f4fb9fcbbbbe75e24 Message-Id: <20221010101353.80A1B385800B@sourceware.org> Date: Mon, 10 Oct 2022 10:13:53 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Dba380b3e5162= e89c4c81a73f4fb9fcbbbbe75e24 commit ba380b3e5162e89c4c81a73f4fb9fcbbbbe75e24 Author: Tom Tromey Date: Mon Jul 25 14:06:34 2022 -0300 Introduce frame_info_ptr smart pointer class =20 This adds frame_info_ptr, a smart pointer class. Every instance of the class is kept on an intrusive list. When reinit_frame_cache is called, the list is traversed and all the pointers are invalidated. This should help catch the typical GDB bug of keeping a frame_info pointer alive where a frame ID was needed instead. =20 Co-Authored-By: Bruno Larsen Approved-by: Tom Tomey Diff: --- gdb/frame-info.h | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ gdb/frame.c | 6 ++ gdb/frame.h | 2 + 3 files changed, 187 insertions(+) diff --git a/gdb/frame-info.h b/gdb/frame-info.h new file mode 100644 index 00000000000..195aa5ccf03 --- /dev/null +++ b/gdb/frame-info.h @@ -0,0 +1,179 @@ +/* Frame info pointer + + Copyright (C) 2022 Free Software Foundation, Inc. + + This file is part of GDB. + + This program 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 of the License, or + (at your option) any later version. + + This program 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . = */ + +#ifndef GDB_FRAME_INFO_H +#define GDB_FRAME_INFO_H + +#include "gdbsupport/intrusive_list.h" + +struct frame_info; + +extern void reinit_frame_cache (); + +/* A wrapper for "frame_info *". frame_info objects are invalidated + whenever reinit_frame_cache is called. This class arranges to + invalidate the pointer when appropriate. This is done to help + detect a GDB bug that was relatively common. + + A small amount of code must still operate on raw pointers, so a + "get" method is provided. However, you should normally not use + this in new code. */ + +class frame_info_ptr : public intrusive_list_node +{ +public: + /* Create a frame_info_ptr from a raw pointer. */ + explicit frame_info_ptr (struct frame_info *ptr) + : m_ptr (ptr) + { + frame_list.push_back (*this); + } + + /* Create a null frame_info_ptr. */ + frame_info_ptr () + { + frame_list.push_back (*this); + } + + frame_info_ptr (std::nullptr_t) + { + frame_list.push_back (*this); + } + + frame_info_ptr (const frame_info_ptr &other) + : m_ptr (other.m_ptr) + { + frame_list.push_back (*this); + } + + frame_info_ptr (frame_info_ptr &&other) + : m_ptr (other.m_ptr) + { + other.m_ptr =3D nullptr; + frame_list.push_back (*this); + } + + ~frame_info_ptr () + { + frame_list.erase (frame_list.iterator_to (*this)); + } + + frame_info_ptr &operator=3D (const frame_info_ptr &other) + { + m_ptr =3D other.m_ptr; + return *this; + } + + frame_info_ptr &operator=3D (std::nullptr_t) + { + m_ptr =3D nullptr; + return *this; + } + + frame_info_ptr &operator=3D (frame_info_ptr &&other) + { + m_ptr =3D other.m_ptr; + other.m_ptr =3D nullptr; + return *this; + } + + frame_info *operator-> () const + { + return m_ptr; + } + + /* Fetch the underlying pointer. Note that new code should + generally not use this -- avoid it if at all possible. */ + frame_info *get () const + { + return m_ptr; + } + + /* This exists for compatibility with pre-existing code that checked + a "frame_info *" using "!". */ + bool operator! () const + { + return m_ptr =3D=3D nullptr; + } + + /* This exists for compatibility with pre-existing code that checked + a "frame_info *" like "if (ptr)". */ + explicit operator bool () const + { + return m_ptr !=3D nullptr; + } + + /* Invalidate this pointer. */ + void invalidate () + { + m_ptr =3D nullptr; + } + +private: + + /* The underlying pointer. */ + frame_info *m_ptr =3D nullptr; + + + /* All frame_info_ptr objects are kept on an intrusive list. + This keeps their construction and destruction costs + reasonably small. */ + static intrusive_list frame_list; + + /* A friend so it can invalidate the pointers. */ + friend void reinit_frame_cache (); +}; + +static inline bool +operator=3D=3D (const frame_info *self, const frame_info_ptr &other) +{ + return self =3D=3D other.get (); +} + +static inline bool +operator=3D=3D (const frame_info_ptr &self, const frame_info_ptr &other) +{ + return self.get () =3D=3D other.get (); +} + +static inline bool +operator=3D=3D (const frame_info_ptr &self, const frame_info *other) +{ + return self.get () =3D=3D other; +} + +static inline bool +operator!=3D (const frame_info *self, const frame_info_ptr &other) +{ + return self !=3D other.get (); +} + +static inline bool +operator!=3D (const frame_info_ptr &self, const frame_info_ptr &other) +{ + return self.get () !=3D other.get (); +} + +static inline bool +operator!=3D (const frame_info_ptr &self, const frame_info *other) +{ + return self.get () !=3D other; +} + +#endif /* GDB_FRAME_INFO_H */ diff --git a/gdb/frame.c b/gdb/frame.c index 8df5feb4825..44cb52910f9 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -56,6 +56,9 @@ static struct frame_info *sentinel_frame; /* Number of calls to reinit_frame_cache. */ static unsigned int frame_cache_generation =3D 0; =20 +/* See frame-info.h. */ +intrusive_list frame_info_ptr::frame_list; + /* See frame.h. */ =20 unsigned int @@ -2006,6 +2009,9 @@ reinit_frame_cache (void) select_frame (NULL); frame_stash_invalidate (); =20 + for (frame_info_ptr &iter : frame_info_ptr::frame_list) + iter.invalidate (); + frame_debug_printf ("generation=3D%d", frame_cache_generation); } =20 diff --git a/gdb/frame.h b/gdb/frame.h index 75bb3bd2aa0..9ad2599331f 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -20,6 +20,8 @@ #if !defined (FRAME_H) #define FRAME_H 1 =20 +#include "frame-info.h" + /* The following is the intended naming schema for frame functions. It isn't 100% consistent, but it is approaching that. Frame naming schema: