Bug 204411 - [JSCOnly] 32-bits warning on memset of JSValue
Summary: [JSCOnly] 32-bits warning on memset of JSValue
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Paulo Matos
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2019-11-20 07:33 PST by Caio Lima
Modified: 2020-03-05 00:55 PST (History)
13 users (show)

See Also:


Attachments
Patch (1.41 KB, patch)
2019-11-22 01:52 PST, Paulo Matos
no flags Details | Formatted Diff | Diff
Patch (1.44 KB, patch)
2019-11-22 06:33 PST, Paulo Matos
no flags Details | Formatted Diff | Diff
Patch (2.07 KB, patch)
2019-11-22 09:51 PST, Paulo Matos
no flags Details | Formatted Diff | Diff
Patch (2.05 KB, patch)
2019-12-02 00:28 PST, Paulo Matos
no flags Details | Formatted Diff | Diff
Patch (2.81 KB, patch)
2019-12-06 04:54 PST, Paulo Matos
no flags Details | Formatted Diff | Diff
Patch (3.10 KB, patch)
2019-12-06 04:59 PST, Paulo Matos
no flags Details | Formatted Diff | Diff
Patch (2.83 KB, patch)
2019-12-09 03:34 PST, Paulo Matos
no flags Details | Formatted Diff | Diff
Patch (1.45 KB, patch)
2020-03-04 03:34 PST, Paulo Matos
no flags Details | Formatted Diff | Diff
Patch (1.46 KB, patch)
2020-03-04 23:59 PST, Paulo Matos
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Caio Lima 2019-11-20 07:33:15 PST
This is current warning:

```
[42/54] Building CXX object Source/JavaScriptCore/CMakeFiles/JavaScriptCore.dir/__/__/DerivedSources/JavaScriptCore/unified-sources/UnifiedSource-f2e18ffc-17.cpp.o
In file included from ../../Source/JavaScriptCore/heap/Heap.h:31,
                 from ../../Source/JavaScriptCore/heap/DeferGC.h:29,
                 from ../../Source/JavaScriptCore/runtime/ConcurrentJSLock.h:28,
                 from ../../Source/JavaScriptCore/runtime/VM.h:34,
                 from ../../Source/JavaScriptCore/interpreter/CallFrame.h:30,
                 from ../../Source/JavaScriptCore/runtime/ArgList.h:24,
                 from ../../Source/JavaScriptCore/runtime/JSArray.h:23,
                 from ../../Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h:29,
                 from ../../Source/JavaScriptCore/runtime/JSGlobalObject.h:24,
                 from ../../Source/JavaScriptCore/runtime/JSFixedArray.h:28,
                 from ../../Source/JavaScriptCore/runtime/JSFixedArray.cpp:27,
                 from DerivedSources/JavaScriptCore/unified-sources/UnifiedSource-f2e18ffc-17.cpp:1:
../../Source/JavaScriptCore/heap/GCMemoryOperations.h: In instantiation of ‘void JSC::gcSafeZeroMemory(T*, size_t) [with T = JSC::JSValue; size_t = unsigned int]’:
../../Source/JavaScriptCore/runtime/RegExpMatchesArray.h:97:123:   required from here
../../Source/JavaScriptCore/heap/GCMemoryOperations.h:307:11: warning: ‘void* memset(void*, int, size_t)’ clearing an object of non-trivial type ‘class JSC::JSValue’; use assignment or value-initialization instead [-Wclass-memaccess]
     memset(dst, 0, bytes);
     ~~~~~~^~~~~~~~~~~~~~~
In file included from ../../Source/JavaScriptCore/bytecode/SpeculatedType.h:32,
                 from ../../Source/JavaScriptCore/runtime/IndexingType.h:28,
                 from ../../Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h:28,
                 from ../../Source/JavaScriptCore/runtime/JSGlobalObject.h:24,
                 from ../../Source/JavaScriptCore/runtime/JSFixedArray.h:28,
                 from ../../Source/JavaScriptCore/runtime/JSFixedArray.cpp:27,
                 from DerivedSources/JavaScriptCore/unified-sources/UnifiedSource-f2e18ffc-17.cpp:1:
../../Source/JavaScriptCore/runtime/JSCJSValue.h:136:7: note: ‘class JSC::JSValue’ declared here
 class JSValue {
       ^~~~~~~

```
Comment 1 Paulo Matos 2019-11-22 01:52:21 PST
Created attachment 384132 [details]
Patch
Comment 2 Paulo Matos 2019-11-22 02:30:44 PST
Uploaded patch to the wrong bug. :( Apologies.
Comment 3 Paulo Matos 2019-11-22 06:33:24 PST
Created attachment 384148 [details]
Patch
Comment 4 Paulo Matos 2019-11-22 06:34:40 PST
Hopefully it is now the right patch. :-)
Comment 5 Caio Lima 2019-11-22 06:42:33 PST
Comment on attachment 384148 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384148&action=review

> Source/JavaScriptCore/heap/GCMemoryOperations.h:309
> +        bitwise_cast<volatile uint32_t*>(dst)[i] = 0;

What about casting `dst` to `void*`? The we would have  `memset(bitwise_cast<void*>(dst), 0, bytes);`.
Comment 6 Paulo Matos 2019-11-22 06:48:28 PST
(In reply to Caio Lima from comment #5)
> Comment on attachment 384148 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=384148&action=review
> 
> > Source/JavaScriptCore/heap/GCMemoryOperations.h:309
> > +        bitwise_cast<volatile uint32_t*>(dst)[i] = 0;
> 
> What about casting `dst` to `void*`? The we would have 
> `memset(bitwise_cast<void*>(dst), 0, bytes);`.

Actually using memset here is always bad because GCC can potentially optimize it away. Instead, we could potentially use std::fill but I thought it would fit better with the code to do it as x86_64 does it.

At the same time, I am still looking at this and wondering if this is correct, because although I haven't seen test failures yet, I think the JSVALUE in 32bits are two 64bits, in which case, we might need to double the count.
Comment 7 Caio Lima 2019-11-22 07:03:31 PST
Comment on attachment 384148 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384148&action=review

>>> Source/JavaScriptCore/heap/GCMemoryOperations.h:309
>>> +        bitwise_cast<volatile uint32_t*>(dst)[i] = 0;
>> 
>> What about casting `dst` to `void*`? The we would have  `memset(bitwise_cast<void*>(dst), 0, bytes);`.
> 
> Actually using memset here is always bad because GCC can potentially optimize it away. Instead, we could potentially use std::fill but I thought it would fit better with the code to do it as x86_64 does it.
> 
> At the same time, I am still looking at this and wondering if this is correct, because although I haven't seen test failures yet, I think the JSVALUE in 32bits are two 64bits, in which case, we might need to double the count.

sizeof(JSValue) on 32-bits is also 8 bytes (https://github.com/caiolima/webkit/blob/master/Source/JavaScriptCore/runtime/JSCJSValue.h#L344). The difference from JSValue64 is the enconding of values. On 32-bits we use high 32-bits as the tag and the other 32-bits as the payload. One thing that I'm missing here is what's bad about GCC optimizing `memset`? Is it possible to remove this code with DCE or something like that?
Comment 8 Paulo Matos 2019-11-22 08:28:16 PST
(In reply to Caio Lima from comment #7)
> Comment on attachment 384148 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=384148&action=review
> 
> >>> Source/JavaScriptCore/heap/GCMemoryOperations.h:309
> >>> +        bitwise_cast<volatile uint32_t*>(dst)[i] = 0;
> >> 
> >> What about casting `dst` to `void*`? The we would have  `memset(bitwise_cast<void*>(dst), 0, bytes);`.
> > 
> > Actually using memset here is always bad because GCC can potentially optimize it away. Instead, we could potentially use std::fill but I thought it would fit better with the code to do it as x86_64 does it.
> > 
> > At the same time, I am still looking at this and wondering if this is correct, because although I haven't seen test failures yet, I think the JSVALUE in 32bits are two 64bits, in which case, we might need to double the count.
> 
> sizeof(JSValue) on 32-bits is also 8 bytes
> (https://github.com/caiolima/webkit/blob/master/Source/JavaScriptCore/
> runtime/JSCJSValue.h#L344). The difference from JSValue64 is the enconding
> of values. On 32-bits we use high 32-bits as the tag and the other 32-bits
> as the payload. 

I thought that could be the case, which is why I mentioned my patch is probably broken even though no tests were seen to fail.

> One thing that I'm missing here is what's bad about GCC
> optimizing `memset`? Is it possible to remove this code with DCE or
> something like that?

If gcc optimizes memset away, then it won't zero the memory. And this is a security issue. Yes, DCE can in GCC eliminate the memset.
Comment 9 Paulo Matos 2019-11-22 09:51:19 PST
Created attachment 384163 [details]
Patch
Comment 10 Mark Lam 2019-11-22 10:13:33 PST
Comment on attachment 384163 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384163&action=review

r=me with fix.

> Source/JavaScriptCore/heap/GCMemoryOperations.h:256
> +    RELEASE_ASSERT(bytes % 8 == 0);

Please remove this RELEASE_ASSERT.  It's not necessarily free and it's redundant with the one at the top of gcSafeZeroMemory().  You can make it a debug ASSERT.
Comment 11 Saam Barati 2019-11-30 16:41:22 PST
Comment on attachment 384163 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384163&action=review

> Source/JavaScriptCore/heap/GCMemoryOperations.h:-307
> -    memset(dst, 0, bytes);

Why are we no longer calling memset? That’s faster than the loop. Maybe just silence the warning instead?
Comment 12 Paulo Matos 2019-12-01 23:38:38 PST
(In reply to Saam Barati from comment #11)
> Comment on attachment 384163 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=384163&action=review
> 
> > Source/JavaScriptCore/heap/GCMemoryOperations.h:-307
> > -    memset(dst, 0, bytes);
> 
> Why are we no longer calling memset? That’s faster than the loop. Maybe just
> silence the warning instead?

There's a possibility that the compiler might remove the memset call and the zero'ing of memory won't happen.
Comment 13 Paulo Matos 2019-12-02 00:28:46 PST
Created attachment 384596 [details]
Patch
Comment 14 Mark Lam 2019-12-02 09:17:04 PST
Comment on attachment 384596 [details]
Patch

Wasn't this already landed previously?  Was it rolled out?  If so, why, and why is it ok to land again?
Comment 15 Mark Lam 2019-12-02 09:17:56 PST
(In reply to Mark Lam from comment #14)
> Comment on attachment 384596 [details]
> Patch
> 
> Wasn't this already landed previously?  Was it rolled out?  If so, why, and
> why is it ok to land again?

OK, looks like it was never landed.
Comment 16 Mark Lam 2019-12-02 09:20:08 PST
Comment on attachment 384596 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384596&action=review

> Source/JavaScriptCore/ChangeLog:9
> +        Implemented alternative to memset, and refactored solutions.
> +        Fixes warning on 32bit builds.

It's probably worth adding a comment here that a compiler may choose to optimize away the memset (given Saam's question), or elaborate on what the warning is if it is related.
Comment 17 Mark Lam 2019-12-02 09:25:50 PST
Comment on attachment 384596 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384596&action=review

> Source/JavaScriptCore/heap/GCMemoryOperations.h:311
>          bitwise_cast<volatile uint64_t*>(dst)[i] = 0;

Please also change this #else case to use gcSafeZeroMemoryHelper(dst, bytes) since it is identical code.
Comment 18 Paulo Matos 2019-12-06 04:54:28 PST
Created attachment 385003 [details]
Patch
Comment 19 Paulo Matos 2019-12-06 04:59:06 PST
Created attachment 385004 [details]
Patch
Comment 20 Paulo Matos 2019-12-06 04:59:49 PST
(In reply to Mark Lam from comment #17)
> Comment on attachment 384596 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=384596&action=review
> 
> > Source/JavaScriptCore/heap/GCMemoryOperations.h:311
> >          bitwise_cast<volatile uint64_t*>(dst)[i] = 0;
> 
> Please also change this #else case to use gcSafeZeroMemoryHelper(dst, bytes)
> since it is identical code.

Mark, sorry for the delay on this. I hope all concerns have now been taken care of.
Comment 21 Darin Adler 2019-12-06 12:32:38 PST
Comment on attachment 385004 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=385004&action=review

> Source/JavaScriptCore/heap/GCMemoryOperations.h:277
> +    return;

Seems that using unconditional return like this could eventually lead to unreachable code warnings. Can we use #else instead of return?
Comment 22 Paulo Matos 2019-12-09 03:34:19 PST
Created attachment 385142 [details]
Patch
Comment 23 Paulo Matos 2019-12-09 05:44:33 PST
(In reply to Darin Adler from comment #21)
> Comment on attachment 385004 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=385004&action=review
> 
> > Source/JavaScriptCore/heap/GCMemoryOperations.h:277
> > +    return;
> 
> Seems that using unconditional return like this could eventually lead to
> unreachable code warnings. Can we use #else instead of return?

Right - well thought out. I have updated the patch.
Comment 24 Saam Barati 2019-12-12 12:02:44 PST
Comment on attachment 384163 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384163&action=review

>>> Source/JavaScriptCore/heap/GCMemoryOperations.h:-307
>>> -    memset(dst, 0, bytes);
>> 
>> Why are we no longer calling memset? That’s faster than the loop. Maybe just silence the warning instead?
> 
> There's a possibility that the compiler might remove the memset call and the zero'ing of memory won't happen.

How? Why could the compiler delete memset?
Comment 25 Paulo Matos 2020-01-06 02:47:19 PST
(In reply to Saam Barati from comment #24)
> Comment on attachment 384163 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=384163&action=review
> 
> >>> Source/JavaScriptCore/heap/GCMemoryOperations.h:-307
> >>> -    memset(dst, 0, bytes);
> >> 
> >> Why are we no longer calling memset? That’s faster than the loop. Maybe just silence the warning instead?
> > 
> > There's a possibility that the compiler might remove the memset call and the zero'ing of memory won't happen.
> 
> How? Why could the compiler delete memset?

Saam, sorry for the delay.
See Notes in https://en.cppreference.com/w/c/string/byte/memset:
Quote:
-
memset may be optimized away (under the as-if rules) if the object modified by this function is not accessed again for the rest of its lifetime (e.g. gcc bug 8537). For that reason, this function cannot be used to scrub memory (e.g. to fill an array that stored a password with zeroes). This optimization is prohibited for memset_s: it is guaranteed to perform the memory write. Third-party solutions for that include FreeBSD explicit_bzero or Microsoft SecureZeroMemory.
-

memset should not be used for safe zero'ing, which is why memset_s exists.
I have found this explanation as well: 
https://www.cryptologie.net/article/419/zeroing-memory-compiler-optimizations-and-memset_s/
Comment 26 Paulo Matos 2020-01-08 07:16:44 PST
ping for r+/cq+ if there are no further issues?
Comment 27 Paulo Matos 2020-03-02 06:03:35 PST
ping?
Comment 28 Yusuke Suzuki 2020-03-02 11:10:50 PST
Comment on attachment 384163 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=384163&action=review

>>>>> Source/JavaScriptCore/heap/GCMemoryOperations.h:-307
>>>>> -    memset(dst, 0, bytes);
>>>> 
>>>> Why are we no longer calling memset? That’s faster than the loop. Maybe just silence the warning instead?
>>> 
>>> There's a possibility that the compiler might remove the memset call and the zero'ing of memory won't happen.
>> 
>> How? Why could the compiler delete memset?
> 
> Saam, sorry for the delay.
> See Notes in https://en.cppreference.com/w/c/string/byte/memset:
> Quote:
> -
> memset may be optimized away (under the as-if rules) if the object modified by this function is not accessed again for the rest of its lifetime (e.g. gcc bug 8537). For that reason, this function cannot be used to scrub memory (e.g. to fill an array that stored a password with zeroes). This optimization is prohibited for memset_s: it is guaranteed to perform the memory write. Third-party solutions for that include FreeBSD explicit_bzero or Microsoft SecureZeroMemory.
> -
> 
> memset should not be used for safe zero'ing, which is why memset_s exists.
> I have found this explanation as well: 
> https://www.cryptologie.net/article/419/zeroing-memory-compiler-optimizations-and-memset_s/

I think this "memset" issue is typically tight to the security issues. And in this case, this is unrelated.
The issue happens when zeroing the value which can contain security-token etc. But it is not scratched (https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-yang.pdf).
In this case, I think it does not matter. We are not using memset to the security related thing, it is used for GC memory's clearing. And if it is read by GC, which means it is escaped from the allocation, so GCC never removes this memset.
Is my understanding correct?
Comment 29 Paulo Matos 2020-03-04 02:45:11 PST
(In reply to Yusuke Suzuki from comment #28)
> 
> I think this "memset" issue is typically tight to the security issues. And
> in this case, this is unrelated.
> The issue happens when zeroing the value which can contain security-token
> etc. But it is not scratched
> (https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-yang.
> pdf).
> In this case, I think it does not matter. We are not using memset to the
> security related thing, it is used for GC memory's clearing. And if it is
> read by GC, which means it is escaped from the allocation, so GCC never
> removes this memset.
> Is my understanding correct?


Hi Yusuke,

Thanks for the comments on this. I think you are correct. I was looking at the code and at how DSE deals with this in GCC8 and it looks like it won't be removed. Unsure exactly why but my guess it that GCC might not be able to prove that the address is not read or because it's inside a template. Usually GCC can be quite aggressive in removing stores like this in C code. For example:
https://godbolt.org/z/TYQeqx

But it is certainly true that this is not a security concern for us and as far as I understand this code (although first time looking at GC), it wouldn't be a problem if indeed GCC removes the store.

I will propose a simpler patch where I cast the dst pointer to a (char *) to avoid the error of memsetting a non-POD type.
Comment 30 Paulo Matos 2020-03-04 03:34:40 PST
Created attachment 392401 [details]
Patch
Comment 31 Alex Christensen 2020-03-04 09:17:44 PST
Comment on attachment 392401 [details]
Patch

We prefer C++ style casts.
reinterpret_cast<char*>(dst)
Comment 32 Yusuke Suzuki 2020-03-04 13:13:06 PST
r=me too, and agree with Alex. Let's use C++ style cast.
Comment 33 Paulo Matos 2020-03-04 23:59:01 PST
Created attachment 392541 [details]
Patch
Comment 34 Paulo Matos 2020-03-04 23:59:35 PST
(In reply to Yusuke Suzuki from comment #32)
> r=me too, and agree with Alex. Let's use C++ style cast.

Thanks. Sure
Comment 35 Mark Lam 2020-03-05 00:07:20 PST
Comment on attachment 392541 [details]
Patch

r=me
Comment 36 WebKit Commit Bot 2020-03-05 00:54:54 PST
Comment on attachment 392541 [details]
Patch

Clearing flags on attachment: 392541

Committed r257908: <https://trac.webkit.org/changeset/257908>
Comment 37 WebKit Commit Bot 2020-03-05 00:54:56 PST
All reviewed patches have been landed.  Closing bug.
Comment 38 Radar WebKit Bug Importer 2020-03-05 00:55:20 PST
<rdar://problem/60075573>