From: Doug Evans <dje@google.com>
To: Pedro Alves <palves@redhat.com>, Joel Brobecker <brobecker@adacore.com>
Cc: gdb-patches <gdb-patches@sourceware.org>
Subject: Re: [RFA] Ensure result of make_cleanup is never NULL.
Date: Tue, 17 Apr 2012 23:12:00 -0000 [thread overview]
Message-ID: <CADPb22Qbp=7zsRFe=by5O3zV8VBaecYhwMjGHWA9Z_jCoTSjtQ@mail.gmail.com> (raw)
In-Reply-To: <CADPb22SfUk5s9JSSBvUTWVyhoiEqO4Gi+VNO-9MwH6rqW8qQ3g@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2131 bytes --]
On Mon, Apr 16, 2012 at 8:21 AM, Doug Evans <dje@google.com> wrote:
>
> On Apr 16, 2012 7:58 AM, "Pedro Alves" <palves@redhat.com> wrote:
>>
>> On 04/16/2012 03:40 PM, Joel Brobecker wrote:
>>
>> >> +/* A fencepost used to mark the end of a cleanup chain.
>> >> + The value is chosen to be non-NULL so that make_cleanup never
>> >> returns NULL,
>> >> + and cause a segv if dereferenced. */
>> >> +#define CLEANUP_FENCEPOST ((struct cleanup *) 1)
>> >
>> > Just a tiny idea, not really important, but JIC: Could we use an enum
>> > intead of a define so that GDB prints "CLEANUP_FENCEPOST" rather than
>> > a numeric value when we print a cleanup pointer that's the fencepost?
>>
>>
>> No, because what you'll be printing will have type struct cleanup pointer,
>> not
>> whatever enum it was cast from.
>>
>> I see at least two ways to get something like that:
>>
>> - a gdb specific pretty printer for cleanups.
>>
>> - Make the sentinel a real object:
>>
>> static struct cleanup sentinel_cleanup;
>> #define CLEANUP_FENCEPOST &sentinel_cleanup
>>
>> And get Tromey's "set print symbol" patch in, which IIRC/IIUC, the
>> latest version makes GDB print the symbol name corresponding
>> to addresses by default. Then gdb would print something like:
>>
>> (gdb) p old_chain
>> $1 = 0xfoobar <sentinel_cleanup>
>>
>> --
>> Pedro Alves
>
> That was my other plan. I can do that instead.
How about this?
2012-04-17 Doug Evans <dje@google.com>
* cleanups.h (struct cleanup): Move to cleanups.c.
(make_cleanup_dtor_ftype): New typedef.
(make_cleanup_dtor): Use it.
(ALL_CLEANUPS): Replace with ...
(all_cleanups): ... this. Declare. All uses updated.
* cleanups.c (cleanup_sentinel): New static global.
(CLEANUP_SENTINEL): Define.
(cleanup_chain, final_cleanup_chain): Initialize to CLEANUP_SENTINEL.
(make_my_cleanup2): Assert result is non-NULL.
(all_cleanups): New function.
(save_my_cleanups): Initialize new chain to CLEANUP_SENTINEL instead
of NULL.
[-- Attachment #2: gdb-120417-cleanups-sentinel-1.patch.txt --]
[-- Type: text/plain, Size: 8221 bytes --]
2012-04-17 Doug Evans <dje@google.com>
* cleanups.h (struct cleanup): Move to cleanups.c.
(make_cleanup_dtor_ftype): New typedef.
(make_cleanup_dtor): Use it.
(ALL_CLEANUPS): Replace with ...
(all_cleanups): ... this. Declare. All uses updated.
* cleanups.c: #include "gdb_assert.h".
(cleanup_sentinel): New static global.
(CLEANUP_SENTINEL): Define.
(cleanup_chain, final_cleanup_chain): Initialize to CLEANUP_SENTINEL.
(make_my_cleanup2): Assert result is non-NULL.
(all_cleanups): New function.
(save_my_cleanups): Initialize new chain to CLEANUP_SENTINEL instead
of NULL.
Index: cleanups.c
===================================================================
RCS file: /cvs/src/src/gdb/cleanups.c,v
retrieving revision 1.2
diff -u -p -r1.2 cleanups.c
--- cleanups.c 17 Apr 2012 21:24:47 -0000 1.2
+++ cleanups.c 17 Apr 2012 22:46:10 -0000
@@ -18,15 +18,50 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "gdb_assert.h"
+
+/* The cleanup list records things that have to be undone
+ if an error happens (descriptors to be closed, memory to be freed, etc.)
+ Each link in the chain records a function to call and an
+ argument to give it.
+
+ Use make_cleanup to add an element to the cleanup chain.
+ Use do_cleanups to do all cleanup actions back to a given
+ point in the chain. Use discard_cleanups to remove cleanups
+ from the chain back to a given point, not doing them.
+
+ If the argument is pointer to allocated memory, then you need
+ to additionally set the 'free_arg' member to a function that will
+ free that memory. This function will be called both when the cleanup
+ is executed and when it's discarded. */
+
+struct cleanup
+{
+ struct cleanup *next;
+ void (*function) (void *);
+ void (*free_arg) (void *);
+ void *arg;
+};
+
+/* Used to mark the end of a cleanup chain.
+ The value is chosen so that it:
+ - is non-NULL so that make_cleanup never returns NULL,
+ - causes a segv if dereferenced
+ [though this won't catch errors that a value of, say,
+ ((struct cleanup *) -1) will]
+ - displays as something useful when printed in gdb. */
+static struct cleanup cleanup_sentinel;
+
+/* Handy macro to use when referring to cleanup_sentinel. */
+#define CLEANUP_SENTINEL (&cleanup_sentinel)
/* Chain of cleanup actions established with make_cleanup,
to be executed if an error happens. */
+static struct cleanup *cleanup_chain = CLEANUP_SENTINEL;
-/* Cleaned up after a failed command. */
-static struct cleanup *cleanup_chain;
-
-/* Cleaned up when gdb exits. */
-static struct cleanup *final_cleanup_chain;
+/* Chain of cleanup actions established with make_final_cleanup,
+ to be executed when gdb exits. */
+static struct cleanup *final_cleanup_chain = CLEANUP_SENTINEL;
/* Main worker routine to create a cleanup.
PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
@@ -51,6 +86,7 @@ make_my_cleanup2 (struct cleanup **pmy_c
new->arg = arg;
*pmy_chain = new;
+ gdb_assert (old_chain != NULL);
return old_chain;
}
@@ -120,6 +156,15 @@ do_my_cleanups (struct cleanup **pmy_cha
}
}
+/* Return a value that can be passed to do_cleanups, do_final_cleanups to
+ indicate perform all cleanups. */
+
+struct cleanup *
+all_cleanups (void)
+{
+ return CLEANUP_SENTINEL;
+}
+
/* Discard cleanups and do the actions they describe
until we get back to the point OLD_CHAIN in the cleanup_chain. */
@@ -185,7 +230,7 @@ save_my_cleanups (struct cleanup **pmy_c
{
struct cleanup *old_chain = *pmy_chain;
- *pmy_chain = 0;
+ *pmy_chain = CLEANUP_SENTINEL;
return old_chain;
}
Index: cleanups.h
===================================================================
RCS file: /cvs/src/src/gdb/cleanups.h,v
retrieving revision 1.2
diff -u -p -r1.2 cleanups.h
--- cleanups.h 17 Apr 2012 21:24:47 -0000 1.2
+++ cleanups.h 17 Apr 2012 22:46:10 -0000
@@ -19,28 +19,8 @@
#ifndef CLEANUPS_H
#define CLEANUPS_H
-/* The cleanup list records things that have to be undone
- if an error happens (descriptors to be closed, memory to be freed, etc.)
- Each link in the chain records a function to call and an
- argument to give it.
-
- Use make_cleanup to add an element to the cleanup chain.
- Use do_cleanups to do all cleanup actions back to a given
- point in the chain. Use discard_cleanups to remove cleanups
- from the chain back to a given point, not doing them.
-
- If the argument is pointer to allocated memory, then you need
- to additionally set the 'free_arg' member to a function that will
- free that memory. This function will be called both when the cleanup
- is executed and when it's discarded. */
-
-struct cleanup
- {
- struct cleanup *next;
- void (*function) (void *);
- void (*free_arg) (void *);
- void *arg;
- };
+/* Outside of cleanups.c, this is an opaque type. */
+struct cleanup;
/* NOTE: cagney/2000-03-04: This typedef is strictly for the
make_cleanup function declarations below. Do not use this typedef
@@ -49,21 +29,25 @@ struct cleanup
Calling a f(char*) function with f(void*) is non-portable. */
typedef void (make_cleanup_ftype) (void *);
+/* Function type for the dtor in make_cleanup_dtor. */
+typedef void (make_cleanup_dtor_ftype) (void *);
+
/* WARNING: The result of the "make cleanup" routines is not the intuitive
choice of being a handle on the just-created cleanup. Instead it is an
opaque handle of the cleanup mechanism and represents all cleanups created
- from that point onwards. */
+ from that point onwards.
+ The result is guaranteed to be non-NULL though. */
extern struct cleanup *make_cleanup (make_cleanup_ftype *, void *);
extern struct cleanup *make_cleanup_dtor (make_cleanup_ftype *, void *,
- void (*dtor) (void *));
+ make_cleanup_dtor_ftype *);
extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *);
/* A special value to pass to do_cleanups and do_final_cleanups
to tell them to do all cleanups. */
-#define ALL_CLEANUPS ((struct cleanup *)0)
+extern struct cleanup *all_cleanups (void);
extern void do_cleanups (struct cleanup *);
extern void do_final_cleanups (struct cleanup *);
Index: exceptions.c
===================================================================
RCS file: /cvs/src/src/gdb/exceptions.c,v
retrieving revision 1.50
diff -u -p -r1.50 exceptions.c
--- exceptions.c 4 Jan 2012 08:17:01 -0000 1.50
+++ exceptions.c 17 Apr 2012 22:46:10 -0000
@@ -224,7 +224,7 @@ throw_exception (struct gdb_exception ex
quit_flag = 0;
immediate_quit = 0;
- do_cleanups (ALL_CLEANUPS);
+ do_cleanups (all_cleanups ());
/* Jump to the containing catch_errors() call, communicating REASON
to that call via setjmp's return value. Note that REASON can't
Index: main.c
===================================================================
RCS file: /cvs/src/src/gdb/main.c,v
retrieving revision 1.108
diff -u -p -r1.108 main.c
--- main.c 17 Apr 2012 15:56:21 -0000 1.108
+++ main.c 17 Apr 2012 22:46:10 -0000
@@ -231,7 +231,7 @@ captured_command_loop (void *data)
are not that well behaved. do_cleanups should either be replaced
with a do_cleanups call (to cover the problem) or an assertion
check to detect bad FUNCs code. */
- do_cleanups (ALL_CLEANUPS);
+ do_cleanups (all_cleanups ());
/* If the command_loop returned, normally (rather than threw an
error) we try to quit. If the quit is aborted, catch_errors()
which called this catch the signal and restart the command
Index: top.c
===================================================================
RCS file: /cvs/src/src/gdb/top.c,v
retrieving revision 1.214
diff -u -p -r1.214 top.c
--- top.c 1 Mar 2012 19:30:20 -0000 1.214
+++ top.c 17 Apr 2012 22:46:10 -0000
@@ -1297,8 +1297,9 @@ quit_target (void *arg)
if (write_history_p && history_filename)
write_history (history_filename);
- do_final_cleanups (ALL_CLEANUPS); /* Do any final cleanups before
- exiting. */
+ /* Do any final cleanups before exiting. */
+ do_final_cleanups (all_cleanups ());
+
return 0;
}
next prev parent reply other threads:[~2012-04-17 23:01 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-04-16 5:01 Doug Evans
2012-04-16 10:58 ` Pedro Alves
2012-04-16 14:44 ` Joel Brobecker
2012-04-16 14:58 ` Jan Kratochvil
2012-04-16 15:03 ` Pedro Alves
2012-04-16 20:16 ` Tom Tromey
[not found] ` <CADPb22SfUk5s9JSSBvUTWVyhoiEqO4Gi+VNO-9MwH6rqW8qQ3g@mail.gmail.com>
2012-04-17 23:12 ` Doug Evans [this message]
2012-04-18 1:06 ` Doug Evans
2012-04-18 1:58 ` Joel Brobecker
2012-04-18 9:21 ` Pedro Alves
2012-04-18 9:29 ` Pedro Alves
2012-04-18 14:14 ` Doug Evans
2012-04-18 14:25 ` Pedro Alves
2012-04-18 14:32 ` Doug Evans
2012-04-18 14:36 ` Pedro Alves
2012-04-18 14:38 ` Tom Tromey
2012-04-19 19:24 ` Doug Evans
2012-04-18 9:26 ` Pedro Alves
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CADPb22Qbp=7zsRFe=by5O3zV8VBaecYhwMjGHWA9Z_jCoTSjtQ@mail.gmail.com' \
--to=dje@google.com \
--cc=brobecker@adacore.com \
--cc=gdb-patches@sourceware.org \
--cc=palves@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox