This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] warn on mem calls modifying objects of non-trivial types (PR 80560)
On 05/17/2017 02:55 AM, Martin Sebor wrote:
> On 05/16/2017 04:48 PM, Pedro Alves wrote:
>> On 05/16/2017 08:41 PM, Jason Merrill wrote:
>>
>>> I agree that it makes sense to
>>> check for a trivial assignment operator specifically. I guess we want
>>> a slightly stronger "trivially copyable" that also requires a
>>> non-deleted assignment operator.
>>>
>>> It seems to me that the relevant tests are:
>>>
>>> bcopy/memcpy/memmove want trivally copyable + non-deleted assignment.
>>> bzero/memset want trivial + non-deleted assignment.
>>>
>>> I'm still not convinced we need to consider standard-layout at all.
>>
>> What do you think of warning for memset of types with references?
Having slept, I now realize you had that covered already by the
"non-deleted assignment" requirement... A reference data member
makes the assignment operator be implicitly deleted. Sorry for the noise.
>> While at it, maybe the same reasoning would justify warn of memcpy/memset
>> of types with const data members?
Ditto.
> I did this because objects with references cannot be assigned
> to (the default copy assignment is deleted). So as a baseline
> rule, I made the warning trigger whenever a native assignment
> or copy isn't valid. In the IMO unlikely event that a memcpy
> over a reference is intended, the warning is easy to suppress.
Agreed.
I wondered whether we'll end up wanting to distinguish these cases:
#1 memcpy (T *, const T *src, size_t n);
#2.1 memcpy (T *, const char *src, size_t n); // char, void, std::byte...
#2.2 memcpy (char *, const T *src, size_t n); // char, void, std::byte...
#3 memcpy (T *, const U *src, size_t n);
Where:
- T is a trivially copyable type that still triggers the new warning.
- U is a type unrelated to T, and is not (unsigned) char, void or std::byte.
#1 is the case that looks like copy.
#2.1 and 2.2 may well appear in type-erasing code.
#3 would look like a way to work around aliasing issues and (even though
ISTR that it's OK as GNU extension if T and U are trivial) worthy of a
warning even if T is trivial under the definition of the warning.
Reading your updated patch, I see that you warn already when T is trivial
and U is not trivial, but IIUC, not if U is also trivial, even if
unrelated to T. Anyway, I don't really want to argue about this -- I
started writing this paragraph before actually reading the patch, and
then actually read the patch and was pleasantly surprised with what
I saw. I think it's looking great.
> I used a similar (though not exactly the same) rationale for
> warning for const members. They too cannot be assigned to,
> and letting memset or memcpy silently change them violates
> const-correctnes.
*Nod*
> It's also undefined
I'm not sure, I think there may be nuances, as usual. AFAICS, it's generally
valid to memcpy into trivially copyable types that have const members to/from
untyped/char storage, AFAICS. Might need to apply std::launder afterwards. But it
isn't clear to me, since whether memcpy starts a (trivial) object's lifetime is
up in the air, AFAIK. But I'm not suggesting to really consider that. The rare
specialized code will be able to work around the spurious warning.
> and the immutability
> of such members an optimization opportunity waiting to be
> exploited.
>
*nod*
>>> +Wnon-trivial-memaccess
>>> +C++ ObjC++ Var(warn_nontrival_memaccess) Warning LangEnabledBy(C++
>>> ObjC++, Wall)
>>> +Warn for raw memory writes to objects of non-trivial types.
>>
>> May I suggest renaming the warning (and the description above) from
>> -Wnon-trivial-memaccess to something else that avoids "trivial" in
>> its name? Because it's no longer strictly about "trivial" in the
>> standard C++ sense. The documentation talks about "The safe way",
>> and "does not warn on safe calls", so maybe call it -Wunsafe-memaccess?
>
> I debated whether to rename things (not just the warning but
> also the function that implements it in GCC). Ultimately I
> decided it wasn't necessary because the rules seem close enough
> to be based on some notion of triviality and because no better
> name came to mind. -Wunsafe-memaccess might work. The one mild
> concern I have with it is that it could suggest it might do more
> than simple type checking (e.g., buffer overflow and what not).
> Let's see what Jason thinks.
Yet another motivation of avoiding "trivial" that crossed my mind is that
you may want to enable the warning in C too, e.g., for warning about
the memcpy of types with const members. But C as no concept
of "trivial", everything is "trivial".
>> (I spotted a couple typos in the new patch: "otherwse", "becase", btw.)
>
> I'm a horrible typist. I'll proofread the patch again and fix
> them up before committing it.
Thanks much for working on this. I think this will uncover lots of
latent bugs in many codebases. Looking forward to have this in.
Thanks,
Pedro Alves