Chrome crashes on Android after building with -Oz |
|||||||||
Issue descriptionChrome Version: ToT (after https://codereview.chromium.org/2897283002) OS: Android What steps will reproduce the problem? (1)Start Chrome after building with -Oz What is the expected result? Doesn't crash What happens instead? Crashes with stack: 05-24 14:21:21.980 18720 18720 F DEBUG : backtrace: 05-24 14:21:21.980 18720 18720 F DEBUG : #00 pc 002bd5e6 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net22QuicCryptoClientStream12DoReceiveREJEPKNS_22CryptoHandshakeMessageEPNS_22QuicCryptoClientConfig11CachedStateE+61) 05-24 14:21:21.980 18720 18720 F DEBUG : #01 pc 002bca43 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net22QuicCryptoClientStream15DoHandshakeLoopEPKNS_22CryptoHandshakeMessageE+122) 05-24 14:21:21.980 18720 18720 F DEBUG : #02 pc 002a11d3 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net12CryptoFramer7ProcessEN4base16BasicStringPieceINSt6__ndk112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEENS_11PerspectiveE+454) 05-24 14:21:21.980 18720 18720 F DEBUG : #03 pc 002a0f47 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net12CryptoFramer12ProcessInputEN4base16BasicStringPieceINSt6__ndk112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEENS_11PerspectiveE+74) 05-24 14:21:21.980 18720 18720 F DEBUG : #04 pc 002bf6ad /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net16QuicCryptoStream15OnDataAvailableEv+72) 05-24 14:21:21.980 18720 18720 F DEBUG : #05 pc 002d5d79 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net19QuicStreamSequencer13OnStreamFrameERKNS_15QuicStreamFrameE+372) 05-24 14:21:21.980 18720 18720 F DEBUG : #06 pc 002d4cd5 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net10QuicStream13OnStreamFrameERKNS_15QuicStreamFrameE+320) 05-24 14:21:21.980 18720 18720 F DEBUG : #07 pc 00288829 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net25QuicChromiumClientSession13OnStreamFrameERKNS_15QuicStreamFrameE+152) 05-24 14:21:21.980 18720 18720 F DEBUG : #08 pc 002b756f /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net14QuicConnection13OnStreamFrameERKNS_15QuicStreamFrameE+90) 05-24 14:21:21.980 18720 18720 F DEBUG : #09 pc 002c4075 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net10QuicFramer16ProcessFrameDataEPNS_14QuicDataReaderERKNS_16QuicPacketHeaderE+300) 05-24 14:21:21.981 18720 18720 F DEBUG : #10 pc 002c39f9 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net10QuicFramer17ProcessDataPacketEPNS_14QuicDataReaderERKNS_22QuicPacketPublicHeaderERKNS_19QuicEncryptedPacketEPcj+400) 05-24 14:21:21.981 18720 18720 F DEBUG : #11 pc 002c31e3 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net10QuicFramer13ProcessPacketERKNS_19QuicEncryptedPacketE+398) 05-24 14:21:21.981 18720 18720 F DEBUG : #12 pc 002b90d3 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net14QuicConnection16ProcessUdpPacketERKNS_17QuicSocketAddressES3_RKNS_18QuicReceivedPacketE+458) 05-24 14:21:21.981 18720 18720 F DEBUG : #13 pc 0028b09b /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net25QuicChromiumClientSession8OnPacketERKNS_18QuicReceivedPacketERKNS_17QuicSocketAddressES6_+22) 05-24 14:21:21.981 18720 18720 F DEBUG : #14 pc 0028d7c3 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net24QuicChromiumPacketReader14OnReadCompleteEi+182) 05-24 14:21:21.981 18720 18720 F DEBUG : #15 pc 0028d673 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net24QuicChromiumPacketReader12StartReadingEv+426) 05-24 14:21:21.981 18720 18720 F DEBUG : #16 pc 0028d7e5 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net24QuicChromiumPacketReader14OnReadCompleteEi+216) 05-24 14:21:21.981 18720 18720 F DEBUG : #17 pc 00165b77 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so 05-24 14:21:21.981 18720 18720 F DEBUG : #18 pc 002fc43f /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net14UDPSocketPosix14DoReadCallbackEi+110) 05-24 14:21:21.981 18720 18720 F DEBUG : #19 pc 002fc351 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net14UDPSocketPosix15DidCompleteReadEv+96) 05-24 14:21:21.981 18720 18720 F DEBUG : #20 pc 002fc22f /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libnet.cr.so (_ZN3net14UDPSocketPosix11ReadWatcher28OnFileCanReadWithoutBlockingEi+42) 05-24 14:21:21.981 18720 18720 F DEBUG : #21 pc 000b21a7 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libbase.cr.so (_ZN4base19MessagePumpLibevent22OnLibeventNotificationEisPv+174) 05-24 14:21:21.981 18720 18720 F DEBUG : #22 pc 00122061 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libbase.cr.so 05-24 14:21:21.981 18720 18720 F DEBUG : #23 pc 000b22fd /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libbase.cr.so (_ZN4base19MessagePumpLibevent3RunEPNS_11MessagePump8DelegateE+64) 05-24 14:21:21.981 18720 18720 F DEBUG : #24 pc 000afbe9 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libbase.cr.so (_ZN4base11MessageLoop3RunEv+60) 05-24 14:21:21.982 18720 18720 F DEBUG : #25 pc 000cb421 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libbase.cr.so (_ZN4base7RunLoop3RunEv+100) 05-24 14:21:21.982 18720 18720 F DEBUG : #26 pc 000ed29f /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libbase.cr.so (_ZN4base6Thread3RunEPNS_7RunLoopE+94) 05-24 14:21:21.982 18720 18720 F DEBUG : #27 pc 0075c7fd /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libcontent.cr.so (_ZN7content17BrowserThreadImpl11IOThreadRunEPN4base7RunLoopE+12) 05-24 14:21:21.982 18720 18720 F DEBUG : #28 pc 0075c8e9 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libcontent.cr.so (_ZN7content17BrowserThreadImpl3RunEPN4base7RunLoopE+184) 05-24 14:21:21.982 18720 18720 F DEBUG : #29 pc 000ed609 /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libbase.cr.so (_ZN4base6Thread10ThreadMainEv+424) 05-24 14:21:21.982 18720 18720 F DEBUG : #30 pc 000e876f /data/app/org.chromium.chrome-p7byJKKi6W7PC-BbvAhfJQ==/lib/arm/libbase.cr.so 05-24 14:21:21.982 18720 18720 F DEBUG : #31 pc 00047d9f /system/lib/libc.so (_ZL15__pthread_startPv+22) 05-24 14:21:21.982 18720 18720 F DEBUG : #32 pc 0001b05f /system/lib/libc.so (__start_thread+32)
,
May 24 2017
Link to bot?
,
May 25 2017
clang only, so perhaps lower priority from that. Also root cause has been reverted, so dropping priority.
,
May 25 2017
Do we think this is a compiler issue, or an issue with the QUIC code?
,
May 25 2017
We don't know. Does the stack look like a possible code bug.
,
May 25 2017
I am unable to reproduce so far. This is my args.gn: target_os = "android" is_clang = true symbol_level = 1 use_goma = true target_cpu = "arm64" time ninja -C out/gnand8 chrome_public_apk -j1000 build/android/adb_install_apk.py out/gnand8/apks/ChromePublic.apk
,
May 25 2017
I still can't repro. Trying with the args.gn someone uses who saw this crash. thakis@thakis:~/src/chrome/src$ build/android/adb_install_apk.py out/gnand6/apks/ChromePublic.apk thakis@thakis:~/src/chrome/src$ cat out/gnand6/args.gn target_os = "android" is_clang = true use_goma = true proprietary_codecs=true ffmpeg_branding="Chrome" thakis@thakis:~/src/chrome/src$ ninja -C out/gnand6 chrome_public_apk -j1000 ninja: Entering directory `out/gnand6' ninja: no work to do. thakis@thakis: ~/src/chrome/src$ build/android/adb_install_apk.py out/gnand6/apks/ChromePublic.apk Chrome installs fine and runs fine on a Nexus 9 running Android 7.1.1. I'm synced to #474341.
,
May 25 2017
,
May 25 2017
I can reproduce this locally with my "normal" (overcomplicated) config. I'll try to reduce it to see if it still crashes.
,
May 25 2017
Yeah, this crashes for me (not literally at startup but the first time I attempt to load a page) on Nexus 6 running 7.x, with just: use_goma = true target_os = "android" is_clang = true
,
May 25 2017
I'll try in a clank build tomorrow. Which target are you building, which apk do you copy over?
,
May 25 2017
chrome_public_apk, installing ChromePublic.apk. I am technically using a clankium tree here but I'm building a public target so there shouldn't actually be much different..
,
May 26 2017
torne's binary also doesn't crash on the Nexus 9 I used for testing. I can reproduce the crash on Torne's Nexus 6.
,
May 26 2017
$ build/android/adb_gdb_chrome_public --output-directory=out/gnand6 --adb=third_party/android_tools/sdk/platform-tools/adb
# (takes several minutes)
(gdb) handle SIG33 nostop noprint pass
(gdb) c
Thread 31 "Thread-3" received signal SIGBUS, Bus error.
[Switching to Thread 9499.9576]
net::QuicCryptoClientStream::DoReceiveREJ (this=0x868bc800, in=0x868bc940, cached=0x93684220) at ../../net/quic/core/quic_crypto_client_stream.cc:402
402 if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
(gdb) bt
#0 net::QuicCryptoClientStream::DoReceiveREJ (this=0x868bc800, in=0x868bc940, cached=0x93684220) at ../../net/quic/core/quic_crypto_client_stream.cc:402
#1 0x8f4c179c in net::QuicCryptoClientStream::DoHandshakeLoop (this=0x868bc800, in=0x868bc940) at ../../net/quic/core/quic_crypto_client_stream.cc:212
#2 0x8f4a7912 in net::CryptoFramer::Process (this=0x868bc924, input=..., perspective=<optimized out>) at ../../net/quic/core/crypto/crypto_framer.cc:270
#3 0x8f4a76bc in net::CryptoFramer::ProcessInput (this=0x868bc924, input=..., perspective=net::Perspective::IS_CLIENT) at ../../net/quic/core/crypto/crypto_framer.cc:73
#4 0x8f4c3f64 in net::QuicCryptoStream::OnDataAvailable (this=0x868bc800) at ../../net/quic/core/quic_crypto_stream.cc:68
#5 0x8f4d7fca in net::QuicStreamSequencer::OnStreamFrame (this=0x868bc818, frame=...) at ../../net/quic/core/quic_stream_sequencer.cc:80
#6 0x8f4d70e2 in net::QuicStream::OnStreamFrame (this=0x868bc800, frame=...) at ../../net/quic/core/quic_stream.cc:124
#7 0x8f48faa4 in net::QuicChromiumClientSession::OnStreamFrame (this=0x85c50f00, frame=...) at ../../net/quic/chromium/quic_chromium_client_session.cc:694
#8 0x8f4bcac8 in net::QuicConnection::OnStreamFrame (this=0x846b5000, frame=...) at ../../net/quic/core/quic_connection.cc:683
#9 0x8f4c7d2e in net::QuicFramer::ProcessFrameData (this=0x846b5010, reader=0x85207588, header=...) at ../../net/quic/core/quic_framer.cc:972
#10 0x8f4c77ea in net::QuicFramer::ProcessDataPacket (this=0x846b5010, encrypted_reader=<optimized out>, public_header=..., packet=...,
decrypted_buffer=0x852076c0 "\244\001.\005\222\001AA>0Y\027\303\065\210\341\020\347C\213\302\f\244\314\027\003L>\332H\331J\036\232\322\v\262\063\221,\325w\367tt7\002\347\033m\244\234\nS\fu\246!\262\016P\356E\252\312\067?\354\r^{\357\232\324F\375\335St*\037%9\205֝G\253ΐs$\326\366\257\"\244~", buffer_length=<optimized out>) at ../../net/quic/core/quic_framer.cc:601
#11 0x8f4c71fc in net::QuicFramer::ProcessPacket (this=0x846b5010, packet=...) at ../../net/quic/core/quic_framer.cc:529
#12 0x8f4be382 in net::QuicConnection::ProcessUdpPacket (this=0x846b5000, self_address=..., peer_address=..., packet=...) at ../../net/quic/core/quic_connection.cc:1212
#13 0x8f491ea4 in net::QuicChromiumClientSession::OnPacket (this=0x85c50f00, packet=..., local_address=..., peer_address=...) at ../../net/quic/chromium/quic_chromium_client_session.cc:1593
#14 0x8f494394 in net::QuicChromiumPacketReader::OnReadComplete (this=0x86888d60, result=<optimized out>) at ../../net/quic/chromium/quic_chromium_packet_reader.cc:89
#15 0x8f4942aa in net::QuicChromiumPacketReader::StartReading (this=0x86888d60) at ../../net/quic/chromium/quic_chromium_packet_reader.cc:65
#16 0x8f4943b8 in net::QuicChromiumPacketReader::OnReadComplete (this=0x86888d60, result=<optimized out>) at ../../net/quic/chromium/quic_chromium_packet_reader.cc:94
#17 0x8f37baa8 in base::Callback<void (net::CertDatabase::Observer*), (base::internal::CopyMode)1, (base::internal::RepeatMode)1>::Run(net::CertDatabase::Observer*) const & (this=0x85208074, args=0x546) at ../../base/callback.h:80
#18 0x8f4fc7dc in net::UDPSocketPosix::DoReadCallback (this=<optimized out>, rv=1) at ../../net/socket/udp_socket_posix.cc:592
#19 0x8f4fc6ec in net::UDPSocketPosix::DidCompleteRead (this=0x911e4e88) at ../../net/socket/udp_socket_posix.cc:614
#20 0x8f4fc5fe in net::UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking (this=0x911e4f08) at ../../net/socket/udp_socket_posix.cc:577
#21 0x935c59e0 in base::MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking (fd=138, this=<optimized out>, pump=<optimized out>) at ../../base/message_l
,
May 26 2017
That code goes something like:
const uint32_t* reject_reasons;
size_t num_reject_reasons;
static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
if (in->GetTaglist(kRREJ, &reject_reasons, &num_reject_reasons) ==
QUIC_NO_ERROR) {
uint32_t packed_error = 0;
for (size_t i = 0; i < num_reject_reasons; ++i) {
// HANDSHAKE_OK is 0 and don't report that as error.
if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
and GetTaglist() is here: https://cs.chromium.org/chromium/src/net/quic/core/crypto/crypto_handshake_message.cc?type=cs&l=82 and does
QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
// ...
*out_tags = reinterpret_cast<const QuicTag*>(it->second.data());
*out_len = it->second.size() / sizeof(QuicTag);
return ret;
And QuicTagValueMap is a `typedef std::map<QuicTag, std::string> QuicTagValueMap`. (And a QuicTag is an uint32_t.
So we're casting a string data pointer to a uint32_t and hoping that that works out. Here we get a SIGBUS (i.e. an alignment error) so I'm guessing fate is catching up with us and calling our bluff. This is likely a code bug.
,
May 26 2017
This is almost certainly why it doesn't fail on Nexus 9 - nvidia's denver recompiling microarchitecture probably just doesn't have (or isn't configured to have) ARM's alignment restrictions.
,
May 26 2017
Quic folks: Things work "fine" (as in "no crash, things seem to work") for me with this change:
$ git diff
diff --git a/net/quic/core/crypto/crypto_handshake_message.cc b/net/quic/core/crypto/crypto_handshake_message.cc
index 220c46adfc0d..b08ff56d3cca 100644
--- a/net/quic/core/crypto/crypto_handshake_message.cc
+++ b/net/quic/core/crypto/crypto_handshake_message.cc
@@ -89,6 +89,8 @@ QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag,
ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
} else if (it->second.size() % sizeof(QuicTag) != 0) {
ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ } else if (reinterpret_cast<uintptr_t>(it->second.data()) % sizeof(QuicTag) != 0) {
+ ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
if (ret != QUIC_NO_ERROR) {
However, the Real Bug (tm) is probably that we end up with an unaligned QuicTag list in the value of a QuicTagValueMap in the first place. So the Right Fix (tm) is probably to change the code that creates that list and makes sure that alignment is up to snuff, instead of making the reading code treat this as an error.
Can one of you take this on? Or point me in the right direction?
This blocks -Oz, which in turn is the only blocker I know of for switching chrome/android to clang at this point.
,
May 26 2017
,
May 26 2017
I'm happy to look at this. Question though. What does -Oz do? Is it causing data to be unaligned, or is it causing the read of unaligned data to fail? The way this code works is that a QUIC handshake message on the wire is a map from a 4 byte QuicTag to some sequence of bytes. The format/interpretation of the sequence of bytes depends on the tag (and is really up to the caller). So when populating the map we don't know the type of data, a priori, which I guess is going to complicate whatever we do here...
,
May 26 2017
+agl who original wrote CryptoHandshakeMessage. BTW: Here's the code which populates this map from the wire: https://cs.chromium.org/chromium/src/net/quic/core/crypto/crypto_framer.cc?sq=package:chromium&dr=CSs&l=268
,
May 26 2017
-Oz just changes optimization settings. The current code has the bug, it's just lucky that all android compilers happen to load things into temporaries that are aligned right. (Arm chips care about alignment, Intel chips are generally happy with unaligned reads. But they're UB everywhere.)
,
May 26 2017
Totally agree with you that the code is currently exhibiting undefined behavior. Just trying to understand why it's not currently crashing :) Do I understand correctly that -Oz no longer loads into temporaries that happened to be aligned right? Anyway, I'm working on coming up with a fix...
,
May 26 2017
I didn't look at what exactly changed to cause the problem, sorry.
,
May 28 2017
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/ebba10fb085b8b01e2faa64523bed3e5373f8b5e commit ebba10fb085b8b01e2faa64523bed3e5373f8b5e Author: rch <rch@chromium.org> Date: Sun May 28 04:24:08 2017 Change CryptoHandshakeMessage::GetTaglist to tag a QuicTagVector* instead of a QuicTag** to avoid unaligned read problems on arm. Merge internal change: 157281990 BUG= 726137 Review-Url: https://codereview.chromium.org/2907743003 Cr-Commit-Position: refs/heads/master@{#475255} [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/crypto/crypto_handshake_message.cc [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/crypto/crypto_handshake_message.h [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/crypto/crypto_server_test.cc [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/crypto/crypto_utils.cc [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/crypto/quic_crypto_client_config.cc [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/crypto/quic_crypto_server_config.cc [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/crypto/quic_crypto_server_config_test.cc [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/quic_config.cc [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/quic_crypto_client_stream.cc [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/quic/core/quic_crypto_server_stream.cc [modify] https://crrev.com/ebba10fb085b8b01e2faa64523bed3e5373f8b5e/net/tools/quic/stateless_rejector_test.cc
,
May 29 2017
,
May 29 2017
,
Jun 10 2017
|
|||||||||
►
Sign in to add a comment |
|||||||||
Comment 1 by billorr@chromium.org
, May 24 2017