Bug 84850 - [8 Regression] -Wclass-memaccess on a memcpy in a copy assignment operator with no nontrivial bases or members
Summary: [8 Regression] -Wclass-memaccess on a memcpy in a copy assignment operator wi...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.0
: P1 normal
Target Milestone: 8.0
Assignee: Martin Sebor
URL:
Keywords: diagnostic, patch
Depends on: 84851
Blocks:
  Show dependency treegraph
 
Reported: 2018-03-13 16:27 UTC by Lubos Uhliarik
Modified: 2018-03-21 15:15 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-03-13 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Lubos Uhliarik 2018-03-13 16:27:22 UTC
Hello gcc-c++ team,

I'm trying to build squid with new gcc-c++, and I'm getting following error:

libtool: compile:  g++ -DHAVE_CONFIG_H -I../.. -I../../include -I../../lib -I../../src -I../../include -I/usr/include/libxml2 -I/usr/include/libxml2 -Wall -Wpointer-arith -Wwrite-strings -Wcomments -Wshadow -Woverloaded-virtual -Werror -pipe -D_REENTRANT -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -mcet -fcf-protection -fPIC -c PoolChunked.cc  -fPIC -DPIC -o PoolChunked.o >/dev/null 2>&1
In file included from ../../src/anyp/PortCfg.h:14,
                 from ../../src/MasterXaction.h:13,
                 from ../../src/CommCalls.h:16,
                 from ../../src/comm.h:13,
                 from ../../src/CommRead.h:15,
                 from ../../src/Store.h:15,
                 from old_api.cc:26:
../../src/anyp/TrafficMode.h: In member function 'AnyP::TrafficMode& AnyP::TrafficMode::operator=(const AnyP::TrafficMode&)':
../../src/anyp/TrafficMode.h:26:93: error: 'void* memcpy(void*, const void*, size_t)' writing to an object of type 'class AnyP::TrafficMode' with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Werror=class-memaccess]
     TrafficMode &operator =(const TrafficMode &rhs) { memcpy(this, &rhs, sizeof(TrafficMode)); return *this; }
                                                                                             ^
In file included from ../../src/anyp/PortCfg.h:14,
                 from ../../src/MasterXaction.h:13,
                 from ../../src/CommCalls.h:16,
                 from ../../src/comm.h:13,
                 from ../../src/CommRead.h:15,
                 from ../../src/Store.h:15,
                 from old_api.cc:26:
../../src/anyp/TrafficMode.h:21:7: note: 'class AnyP::TrafficMode' declared here
 class TrafficMode
       ^~~~~~~~~~~
In file included from ../../src/comm/Connection.h:18,
                 from ../../src/anyp/PortCfg.h:15,
                 from ../../src/MasterXaction.h:13,
                 from ../../src/CommCalls.h:16,
                 from ../../src/comm.h:13,
                 from ../../src/CommRead.h:15,
                 from ../../src/Store.h:15,
                 from old_api.cc:26:
../../src/eui/Eui64.h: In member function 'Eui::Eui64& Eui::Eui64::operator=(const Eui::Eui64&)':
../../src/eui/Eui64.h:40:70: error: 'void* memcpy(void*, const void*, size_t)' writing to an object of type 'class Eui::Eui64' with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Werror=class-memaccess]
     Eui64& operator= (const Eui64 &t) {memcpy(this, &t, sizeof(Eui64)); return *this;}
                                                                      ^
../../src/eui/Eui64.h:34:7: note: 'class Eui::Eui64' declared here
 class Eui64
       ^~~~~
cc1plus: all warnings being treated as errors



I guess, in this case, warning should not be printed.
Comment 1 Martin Sebor 2018-03-13 17:29:05 UTC
The warning is designed to allow raw memory access in ctors and dtors of non-trivial classes with no non-trivial bases or members, but the exemption doesn't extend to assignment operators of such classes.  Some such types (including squid's TrafficMode class) use memcpy in the special functions as a shortcut to copy multiple trivial members without having to explicitly enumerate them.  Since this is safe it makes sense to exempt the copy assignment operator as well.  Confirmed with the test case below.

$ cat pr84850.C && gcc -S  -Wall pr84850.C
struct S
{
  bool a, b;
  S ();
  S (const S&);
  ~S ();
  void operator= (const S&);
};

S::S ()
{
  __builtin_memset (this, 0, sizeof *this);
}

S::S (const S &s)
{
  __builtin_memcpy (this, &s, sizeof s);
}

S::~S ()
{
  __builtin_memset (this, 0, sizeof *this);
}

void S::operator= (const S &s)
{
  __builtin_memcpy (this, &s, sizeof s);
}

pr84850.C: In member function ‘void S::operator=(const S&)’:
pr84850.C:27:39: warning: ‘void* __builtin_memcpy(void*, const void*, long unsigned int)’ writing to an object of type ‘struct S’ with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Wclass-memaccess]
   __builtin_memcpy (this, &s, sizeof s);
                                       ^
pr84850.C:1:8: note: ‘struct S’ declared here
 struct S
        ^
Comment 2 Martin Sebor 2018-03-13 17:58:34 UTC
Bug 84851 shows that the exemption for copy ctors is overly simplistic and broad.  Using the same mechanism for copy assignment would not be appropriate because it would compromise the warning and prevent it from detecting some undefined cases.  Adding an exemption for copy assignment will require checking all bases and members to make sure they are trivial.  That makes the solution for this bug dependent on pr84851.
Comment 3 Richard Biener 2018-03-14 13:09:50 UTC
But this one is a regression while PR84851 is an improvement request.
Comment 4 Martin Sebor 2018-03-14 15:13:40 UTC
I have a patch that handles both pr84851 and pr84850.  I don't view this report as a regression any more than the other PR.  The warning does what it was designed to do.  It was just designed to be strict in this case and overly permissive in the other.
Comment 5 Jakub Jelinek 2018-03-14 17:22:24 UTC
So just handle this PR now (warning less; handle copy assignment ops like copy ctors) and deal with the rest (warning more) for stage1.
Comment 6 Martin Sebor 2018-03-20 02:06:51 UTC
Patch: https://gcc.gnu.org/ml/gcc-patches/2018-03/msg00915.html
Comment 7 Martin Sebor 2018-03-21 15:14:34 UTC
Author: msebor
Date: Wed Mar 21 15:14:02 2018
New Revision: 258719

URL: https://gcc.gnu.org/viewcvs?rev=258719&root=gcc&view=rev
Log:
PR c++/84850 - -Wclass-memaccess on a memcpy in a copy assignment operator with no nontrivial bases or members

gcc/cp/ChangeLog:

	PR c++/84850
	* call.c (first_non_public_field): New template and function.
	(first_non_trivial_field): New function.
	(maybe_warn_class_memaccess): Call them.

gcc/testsuite/ChangeLog:

	PR c++/84850
	* g++.dg/Wclass-memaccess-3.C: New test.
	* g++.dg/Wclass-memaccess-4.C: New test.


Added:
    trunk/gcc/testsuite/g++.dg/Wclass-memaccess-3.C
    trunk/gcc/testsuite/g++.dg/Wclass-memaccess-4.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
    trunk/gcc/testsuite/ChangeLog
Comment 8 Martin Sebor 2018-03-21 15:15:42 UTC
Patch committed in r258719 with the fix for bug 84851 present but disabled.  It will be enabled in stage 1 of GCC 9.