[Bug c++/89729] [g++ 8] -Wclass-memaccess warning

2019-03-15 Thread chantry.xavier at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89729

--- Comment #3 from Xavier  ---
(In reply to Martin Sebor from comment #1)

Thanks a lot for the detailed explanation, it's much clearer now.
Wclass-memaccess does look sane.
script_data_t is apparently manipulated from both C and C++ code, which might
explain why it's done this way.
We can either disable the warning in this case or use a (void *) so no problem.

(In reply to Jonathan Wakely from comment #2)
> You should use the gcc-help mailing list for questions like this, because
> you're not reporting a bug.

You're right, sorry about that.

[Bug c++/89729] [g++ 8] -Wclass-memaccess warning

2019-03-15 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89729

--- Comment #2 from Jonathan Wakely  ---
(In reply to Xavier from comment #0)
> There are already many bugs about this one, but since I am not expert on
> C++, I would like to have your advice.

[...]

> What's the correct way in gnu++98 to do this ?

[...]

> The other bugs mention cast to void * as a workaround, this does seem to
> work, even with a simple C cast. Is this also acceptable in my case for both
> memset and memcpy ?

You should use the gcc-help mailing list for questions like this, because
you're not reporting a bug.

[Bug c++/89729] [g++ 8] -Wclass-memaccess warning

2019-03-15 Thread msebor at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89729

Martin Sebor  changed:

   What|Removed |Added

   Keywords||diagnostic
 Status|UNCONFIRMED |RESOLVED
 CC||msebor at gcc dot gnu.org
 Resolution|--- |INVALID

--- Comment #1 from Martin Sebor  ---
Declaring a default ctor for a class like script_data_t in attachment 45975
means that objects of the class need to be constructed and initialized using
the default ctor.  Calling memset to zero-out an object of such a class
suggests the caller might be treating the class as a plain old C struct which
it shouldn't be: it could bypass the ctor and fail to begin the object's
lifetime or break invariants previously established by the ctor.

Similarly, declaring a class copy assignment operator private means that the
class is not meant to be copy-assignable.  Calling memcpy on an object of such
a class could violate invariants established by its ctor/assignment operator.

The warning points out these potential bugs.  It's meant to help avoid them
especially when C code is transitioning to C++, e.g., when an object of C++
class is added as a member of a plain C struct (imagine what might happen if a
std::string member were added to script_data_t).

In the test case in attachment 45975, d2 is initialized on declaration:

  void script_data_init_empty(script_data_t *data)
  {
script_data_t d2; // ctor initializes (e.g., clears)
// p_clear(, 1);   // should not be necessary (done by ctor)
// memcpy(data, , sizeof(d2));   // unsafe

// if data points to an already initialized script_data_t object
// destroy it first:
data->~script_data_t()

// ...and then create a new object in its place by using
// the implicitly provided copy ctor (or just create a new
// one if data points to uninitialized memory):
new (data) script_data_t (d2);
  }

But judging by the name of the function I would expect it to be a no-op in C++:
there should be no need to call it to initialize a script_data_t object: its
ctor does it.  Simply declaring an object of the class initializes it.  The
same is true for objects dynamically allocated via a new expression.  If you
allocate memory for those objects using malloc then initialize them using
placement new as shown above (and remember to destroy them by explicitly
calling the dtor before freeing the memory.

It's also possible (even likely) that script_data_t is poorly designed and that
calling memset/memcpy on it is, in fact, safe and necessary.  A class that
declares a private copy assignment probably isn't meant to be constructible
either and so it should also make its copy constructor inaccessible (by
declaring it private in C++ 98).  Either way, when dealing with a poorly
designed class that can't be easily fixed, casting the pointer to it to void*
before passing it to memcpy/memset suppresses the warning:

  #define p_clear(p, count)   
\
({ (typeof(*(p)) *)memset((void*)(p), 0, sizeof(*(p)) * (count)); })

You can also use #pragma GCC diagnostic to suppress the warning before each
such access (and restore it afterwards):

void script_data_init_empty(script_data_t *data)
{
script_data_t d2;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
p_clear(, 1); // no warning here
#pragma GCC diagnostic pop

memcpy(data, , sizeof(d2));   // warning here
}