diff mbox

[08/16] libiberty.h: Provide a CLEAR_VAR macro

Message ID 1433192664-50156-9-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm June 1, 2015, 9:04 p.m. UTC
include/ChangeLog:
	* libiberty.h (CLEAR_VAR): New macro.
---
 include/libiberty.h | 4 ++++
 1 file changed, 4 insertions(+)

Comments

DJ Delorie June 1, 2015, 9:47 p.m. UTC | #1
> +/* Fill an lvalue with zero bits.  */
> +#define CLEAR_VAR(S) \
> +  do { memset (&(S), 0, sizeof (S)); } while (0)

Hmmm... I don't see the point in this.  The macro is almost as long as
a bare memset() would be, and replaces a well-known function with
something unknown outside this project.  It neither hides a bug in an
OS nor provides a common way to handle a difficult task across
platforms.

You also do NOT want to use memset to zero out a C++ structure that
contains more than just "plain old data" - you could easily corrupt
the structure's hidden data.

Also, pedantically speaking, "all bits zero" is not guaranteed to be
the same as float 0.0, double 0.0, or pointer (void *)0.
David Malcolm June 2, 2015, 1:16 a.m. UTC | #2
On Mon, 2015-06-01 at 17:47 -0400, DJ Delorie wrote:
> > +/* Fill an lvalue with zero bits.  */
> > +#define CLEAR_VAR(S) \
> > +  do { memset (&(S), 0, sizeof (S)); } while (0)
> 
> Hmmm... I don't see the point in this.  The macro is almost as long as
> a bare memset() would be, and replaces a well-known function with
> something unknown outside this project.  It neither hides a bug in an
> OS nor provides a common way to handle a difficult task across
> platforms.

Thanks for looking at this.

FWIW I'm not in love with the name of the macro, but I find it useful.
In the initial version of patches 10 and 12 (state purging within "gas"
and "ld" subdirs) I didn't have this macro, and had about 30 memset
invocations.

There are a couple of ways to mess up such code; consider:

  memset (&statement_list, 0, sizeof (statement_list));
  memset (&stat_save, 0, sizeof (statement_list));

where a bug is hiding: the 2nd memset is using the wrong sizeof, leading
to only part of it being zeroed.  Having a macro for this makes the code
shorter:

  CLEAR_VAR (statement_list);
  CLEAR_VAR (stat_save);

and thus more reliable (my eyes glaze over looking at all the memsets in
the more involved examples).

There's probably another way to mess this up, by forgetting the & on the
first param.

> You also do NOT want to use memset to zero out a C++ structure that
> contains more than just "plain old data" - you could easily corrupt
> the structure's hidden data.

Are you thinking of vtables here, "public" vs "private", or of
inheritance?  FWIW I'm only using this from within binutils, which AFAIK
is pure C (I'm new to binutils).

> Also, pedantically speaking, "all bits zero" is not guaranteed to be
> the same as float 0.0, double 0.0, or pointer (void *)0.

The purpose of the code is to restore the state back to what it was when
the library was first loaded; in the various foo_c_finalize () functions
in patches 10 and 12 I try to only use CLEAR_VAR for structs, and
instead spell out NULL etc for ptrs.  Perhaps CLEAR_STRUCT () might be a
better name?  Also, if this isn't so much a libiberty thing (not being
an OS-compatibility thing), is there a place to put it in internal
support headers?  (in the sense that this would be an implementation
detail, used by both gas and ld)

Thanks
Dave
DJ Delorie June 2, 2015, 1:39 a.m. UTC | #3
> FWIW I'm not in love with the name of the macro, but I find it useful.
> In the initial version of patches 10 and 12 (state purging within "gas"
> and "ld" subdirs) I didn't have this macro, and had about 30 memset
> invocations.

Another option is to save the state as it was initialized, and restore
it as needed.  That way, structures that don't start off all zero will
get "reset" properly.  In this case, you're just talking about a
simple assignment:

  saved_vars = my_vars;
  . . .
  my_vars = saved_vars;

In addition to simplicity, the compiler will check the types for you
to make sure you don't goof up.

> Are you thinking of vtables here, "public" vs "private", or of
> inheritance?

Yes.

>  FWIW I'm only using this from within binutils, which AFAIK is pure
> C (I'm new to binutils).

Ah, but you're putting the macro in libiberty, which *is* used by C++
files.

> > Also, pedantically speaking, "all bits zero" is not guaranteed to be
> > the same as float 0.0, double 0.0, or pointer (void *)0.
> 
> The purpose of the code is to restore the state back to what it was when
> the library was first loaded;

That's not what you're doing, what you're doing is setting it to all
zero, even if the data was non-zero at the start.

> Also, if this isn't so much a libiberty thing (not being an
> OS-compatibility thing), is there a place to put it in internal
> support headers?  (in the sense that this would be an implementation
> detail, used by both gas and ld)

bfd.h might be an option, since it's common to most binutils programs.
diff mbox

Patch

diff --git a/include/libiberty.h b/include/libiberty.h
index b33dd65..93e4131 100644
--- a/include/libiberty.h
+++ b/include/libiberty.h
@@ -699,6 +699,10 @@  extern void stack_limit_increase (unsigned long);
 
 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
 
+/* Fill an lvalue with zero bits.  */
+#define CLEAR_VAR(S) \
+  do { memset (&(S), 0, sizeof (S)); } while (0)
+
 /* Drastically simplified alloca configurator.  If we're using GCC,
    we use __builtin_alloca; otherwise we use the C alloca.  The C
    alloca is always available.  You can override GCC by defining