Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usage of memset with non-trivial types that results in -Wclass-memaccess #12684

Closed
am11 opened this issue May 10, 2019 · 9 comments · Fixed by #74363
Closed

Usage of memset with non-trivial types that results in -Wclass-memaccess #12684

am11 opened this issue May 10, 2019 · 9 comments · Fixed by #74363
Assignees
Milestone

Comments

@am11
Copy link
Member

am11 commented May 10, 2019

Starting with gcc 8, compiler is warning about several usages of memset in case of types that are
non-trivially copyable. This includes structs inheriting struct ZeroInit, usage of FillMemory and ZeroMemory macros (defined in pal.h) and other places which are directly calling the function (although some of those places can make use of the defined macro as it stands).

From release notes (https://www.gnu.org/software/gcc/gcc-8/changes.html):

-Wclass-memaccess warns when objects of non-trivial class types are manipulated in potentially unsafe ways by raw memory functions such as memcpy, or realloc. The warning helps detect calls that bypass user-defined constructors or copy-assignment operators, corrupt virtual table pointers, data members of const-qualified types or references, or member pointers. The warning also detects calls that would bypass access controls to data members.

LLVM has included -Wnontrivial-memaccess for C structs and there are also considerations to add -Wclass-memaccess in future: https://reviews.llvm.org/D45310

Reading the community discussions about practices pertaining to usage of memset with non-POD types and how others have responded to the gcc warning, I think there are three ways to fix this (in descending order of preference):

  1. Call proper ctor, use std:fill and friends for non-trivial data structures.
  2. Cast pointer to void* to circumvent the type check.
  3. Suppress warning in cmake -Wno-class-memaccess.
@mikedn
Copy link
Contributor

mikedn commented May 10, 2019

Call proper ctor

That would be ideal but I'm afraid that at least in the JIT code you'll find some cases that might be difficult to fix like that. So 2. will probably be needed as well, if it doesn't cause other problems.

@jkotas
Copy link
Member

jkotas commented May 18, 2019

How many places do hit this warning - could you please share the list (as gist if it is too long)?

@am11
Copy link
Member Author

am11 commented May 19, 2019

cd coreclr
./build.sh -skiprestore -skipmanaged -gcc &> build-output.txt

# count unique lines
cat build-output.txt | grep class-memaccess | uniq -uc | wc -l
# => 1646

# filter output file with afterLines=2 and replace newline with literal '\n'
CONTENTS=`cat build-output.txt | grep -A 2 class-memaccess | sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g'`

# write gist API request body to a temp file
echo "{\"public\":false,\"files\":{\"class-memaccess.txt\":{\"content\":\"$CONTENTS\"}}}" > class-memaccess-gist.txt

# send to github server using access token
curl -X POST -d @class-memaccess-gist.txt -u <personal-access-token-with-'gist'-scope>:x-oauth-basic https://api.github.com/gists 

gist | raw

@am11
Copy link
Member Author

am11 commented Jan 27, 2020

@jkotas, I have found few places while fixing some of these warnings in cee_wks target, where 204 is being memset() to complex types under #ifdef _DEBUG, e.g.

#ifdef _DEBUG
:

  1. are they (all) in use?
  2. what is the significance of number 204; can we make it 0?

@jkotas
Copy link
Member

jkotas commented Jan 27, 2020

what is the significance of number 204;

It is easy to notice that it is a uninitialized value when debugging. It is why it is done only under _DEBUG.

@jkotas
Copy link
Member

jkotas commented Jan 27, 2020

The specific one you have linked is getting major refactoring in dotnet/coreclr#1828.

@msftgits msftgits transferred this issue from dotnet/coreclr Jan 31, 2020
@msftgits msftgits added this to the Future milestone Jan 31, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 26, 2020
@ericstj ericstj removed the untriaged New issue has not been triaged by the area owner label Jun 25, 2020
mcfadden8 added a commit to LLNL/Umpire that referenced this issue Sep 23, 2021
By type casting the pointer to an AllocatorTableEntry to be 'void*',
this will circumvent the typecheck being done by gcc 8 or higher to
determine whether the object is a POD or not. (see:
dotnet/runtime#12684)

Prior to this change, this warning would be triggered in GCC 10.2.1:
  error: 'void* memset(void*, int, size_t)' clearing an object of
  non-trivial type`

It is unclear why gcc is considering this POD to be non-trivial.
davidbeckingsale pushed a commit to LLNL/Umpire that referenced this issue Sep 23, 2021
By type casting the pointer to an AllocatorTableEntry to be 'void*',
this will circumvent the typecheck being done by gcc 8 or higher to
determine whether the object is a POD or not. (see:
dotnet/runtime#12684)

Prior to this change, this warning would be triggered in GCC 10.2.1:
  error: 'void* memset(void*, int, size_t)' clearing an object of
  non-trivial type`

It is unclear why gcc is considering this POD to be non-trivial.
@RobertHenry6bev
Copy link
Contributor

There are numerous places gcc-12 complains about memset being called to zero the entire object when the object is not Plain Old Data (POD). (The C++ standard haas a more encompassing definition than POD.)

Consider

ZeroMemory(this, sizeof(InteropSyncBlockInfo));

InteropSyncBlockInfo has a lot of non-trivial data, some of which will (likely?) have constructors fired on them, and the memset is a blunt hammer to zero out everything, perhaps leaving embedded objects in an inconsistent and buggy state.

@RobertHenry6bev
Copy link
Contributor

I went through and added gcc diagnostic suppressions throughout the code base as needed to get to compile with gcc12.

There were 41 files changed with ~50 changes. See attached file
robhenry-memaccess-pragma.txt

It is conceivable that the CONTRACT semantics of some of the callers to memset tell some compiler that memset is safe, but gcc certainly doesn't know about that.

@RobertHenry6bev
Copy link
Contributor

/cc @AaronRobinsonMSFT

@AaronRobinsonMSFT AaronRobinsonMSFT self-assigned this Aug 18, 2022
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Aug 22, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Aug 25, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Sep 25, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Development

Successfully merging a pull request may close this issue.

8 participants