New issue
Advanced search Search tips

Issue 681218 link

Starred by 3 users

Issue metadata

Status: Fixed
Owner:
Closed: Apr 2017
Cc:
EstimatedDays: ----
NextAction: ----
OS: Windows
Pri: 2
Type: Bug-Regression

Blocking:
issue 681800



Sign in to add a comment

chrome://memory-exhaust/ does not display correct sad tab on clang built binaries

Project Member Reported by wfh@chromium.org, Jan 13 2017

Issue description

Chrome Version: 57.0.2979.2 (Official Build) canary (64-bit)
OS: Win 10

What steps will reproduce the problem?
(1) go to chrome://memory-exhaust
(2)
(3)

What is the expected result?

Sad tab with "Google Chrome ran out of memory while trying to display this webpage."

What happens instead?

Sad tab with "Something went wrong while displaying this webpage".

Please use labels and text to provide additional information.

Works on 55.0.2883.87 (Official Build) m (64-bit) (Stable Channel) so this is a regression.

For graphics-related bugs, please copy/paste the contents of the about:gpu
page at the end of this report.

 

Comment 1 by wfh@chromium.org, Jan 13 2017

Cc: scottmg@chromium.org
Yes I know, as scottmg would say, I...

♪ Should have put a test on it ♫

Comment 2 by palmer@chromium.org, Jan 13 2017

Labels: OS-Android OS-Chrome OS-Linux OS-Mac

Comment 3 by wfh@chromium.org, Jan 13 2017

Labels: -OS-Linux -OS-Android -OS-Chrome -OS-Mac
weird - I can't repro this with Chromium r443466 57.0.2980.0 (for bisect) so something more subtle must be wrong with my Chrome Canary.

This message only appears on Windows.

Comment 4 by wfh@chromium.org, Jan 14 2017

hmm doing chrome://memory-exhaust gives exit code = 1073741795 in chrome://histograms which is STATUS_ILLEGAL_INSTRUCTION. This makes little sense.

Comment 5 by wfh@chromium.org, Jan 14 2017

Cc: brucedaw...@chromium.org
now I suspect something to do with official builds and optimizations. I will try an official bisect.

Comment 6 by palmer@chromium.org, Jan 14 2017

Cc: -brucedaw...@chromium.org
I was able to reproduce it on Linux, Chrome Beta (56).
Repros for me on Canary here (and not on Stable)

Comment 8 by wfh@chromium.org, Jan 14 2017

The custom "Google Chrome ran out of memory while trying to display this webpage." is only supported on Windows (unless someone else has implemented it on other platforms) so I'm not surprised that you get the standard "Something went wrong while displaying this webpage" on platforms other than Windows.
Oh, but not on another Win Canary -- I suspect Compiler: clang now.

Comment 10 by wfh@chromium.org, Jan 14 2017

Cc: thakis@chromium.org
ah yes, I am also compiler: clang - I hadn't noticed that before. clang can't call ::RaiseException...?

Comment 11 by wfh@chromium.org, Jan 14 2017

Summary: chrome://memory-exhaust/ does not display correct sad tab on clang built binaries (was: chrome://memory-exhaust/ does not display correct sad tab)
yup, confirmed - on another machine running 57.0.2980.0 (Official Build) canary (64-bit) with compiler: MSVC (PGO) chrome://memory-exhaust works fine, so it's definitely something clang related.
It calls malloc in a loop, maybe clang must thinks it's smart and knows something about undefined behaviour so it's allowed to just nuke early.
This looks like the code that corresponds to

    LOG(ERROR)
        << "Intentionally exhausting renderer memory because user navigated to "
        << url.spec();
    ExhaustMemory();

So I don't think it thinks it needs to call ExhaustMemory().

00007ffe`3bc6f396 b902000000      mov     ecx,2
00007ffe`3bc6f39b e8f0ec8efe      call    chrome_child!logging::ShouldCreateLogMessage (00007ffe`3a55e090)
00007ffe`3bc6f3a0 488d1529674901  lea     rdx,[chrome_child!`string' (00007ffe`3d105ad0)]
00007ffe`3bc6f3a7 488d7c2440      lea     rdi,[rsp+40h]
00007ffe`3bc6f3ac 41b81a020000    mov     r8d,21Ah
00007ffe`3bc6f3b2 41b902000000    mov     r9d,2
00007ffe`3bc6f3b8 4889f9          mov     rcx,rdi
00007ffe`3bc6f3bb e810f18efe      call    chrome_child!logging::LogMessage::LogMessage (00007ffe`3a55e4d0)
00007ffe`3bc6f3c0 488d4c2448      lea     rcx,[rsp+48h]
00007ffe`3bc6f3c5 488d152c814901  lea     rdx,[chrome_child!`string' (00007ffe`3d1074f8)]
00007ffe`3bc6f3cc e8d73fcbfd      call    chrome_child!std::operator<<<std::char_traits<char> > (00007ffe`399233a8)
00007ffe`3bc6f3d1 4889c3          mov     rbx,rax
00007ffe`3bc6f3d4 4c89e9          mov     rcx,r13
00007ffe`3bc6f3d7 e8a63d9cfe      call    chrome_child!GURL::spec (00007ffe`3a633182)
00007ffe`3bc6f3dc 4889d9          mov     rcx,rbx
00007ffe`3bc6f3df 4889c2          mov     rdx,rax
00007ffe`3bc6f3e2 e8a9d7cffd      call    chrome_child!std::operator<<<char,std::char_traits<char>,std::allocator<char> > (00007ffe`3996cb90)
00007ffe`3bc6f3e7 4889f9          mov     rcx,rdi
00007ffe`3bc6f3ea e831ed8efe      call    chrome_child!logging::LogMessage::~LogMessage (00007ffe`3a55e120)
00007ffe`3bc6f3ef 0f0b            ud2

It in fact declined to include ExhaustMemory() in the binary, citing concerns that "'twas a silly function":

0:000> x chrome_child!*ExhaustMemory*
0:000> x *!*ExhaustMemory*
0:000>

Comment 15 by wfh@chromium.org, Jan 14 2017

it is indeed a silly function, so clang isn't wrong there.
Running  x='a';while(1)x+='a';  in devtools caused the correct oom display message, so just the debug url that's a problem.
Cc: h...@chromium.org
So, the fact that ExhaustMemory gets optimized away is expected. welcome to the club of "I was trying to fool my compiler around malloc and I lost".
If you start actually dereferencing volatile memory, the compiler should start showing some respect.
In other words I'd do:

void ExhaustMemory() {
  volatile char* ptr;
  for(;;) {
    const size_t kSize = 0x10000000;
    ptr = reinterpret_cast<volatile char*>(malloc(kSize));
    if (!ptr) break;
    ptr[0] = ptr[kSize - 1] + 1;
  }
}

I am sure that there are a dozen carefully written sentences in the C++ specs, full of triple negatives, that make it so that you can't rely on this. But, in my limited experience, this trick has worked so far. 

There are two IMHO disturbing things here:
1) The fact that the function was translated into a "ud2", which is essentially a crash.
I wouldn't have anything to say if the existing ExhaustMemory was optimized as a no-op.
I have something to say (see next point) if gets optimized as a while(true){}, but just learned to deal with that over time. 
I am quite shocked by the fact that it gets translated into a __builtin_trap equivalent (ud2). ^__^
I am thrilled and frightened to understand why here.
I understand why this could have been the case for new/delete (There was a very good internal post I can't find right now, about new/delete and the fact that they are assumed to not fail even if you build with exceptions disabled), but this is a plain old malloc

2) A part of this confusion is generated by the fact that clang/LLVM seems to assume that malloc always returns non-null. While trying to repro this bug, I tried this on clang (both OSX and linux):

-----
void ExhaustMemory() {
  volatile void* ptr = 0;
  do { ptr = malloc(40); } while(ptr);
}

int main() {
 ExhaustMemory();
 return 1;
}
-----
$ clang++ test.cc -O1  -S -o -
	.type	_Z13ExhaustMemoryv,@function
_Z13ExhaustMemoryv:                     # @_Z13ExhaustMemoryv
	.cfi_startproc
# BB#0:                                 # %entry
	.p2align	4, 0x90
.LBB0_1:                                # %do.body
                                        # =>This Inner Loop Header: Depth=1
	jmp	.LBB0_1


Which essentially is a while(true){}. 
And for the records, GCC is way more respectful on this.

Again, would have no objections if this was optimized as a no-op, or if this this was a "new". but this is assuming that malloc would always succeed.

There is a long discussion about this point in:
"[LLVMdev] optimization assumes malloc return is non-null" (https://groups.google.com/forum/#!topic/llvm-dev/lV30rcmF0ss)

and it makes me quite nervous. Because, if I read it correctly, it means that any code like:
x = malloc(...)
if (!x)
  ...
might cause, at best, an abundant laugh to  clang/llvm.

We have that sort of stuff everywhere in the codebase, see https://cs.chromium.org/search/?q=if%5Cs*%5C(.*%5Cbmalloc%5Cb.*+f:%5C.c&sq=package:chromium&type=cs
The only good side is that once we convince the compiler to actually call malloc(), our own implementation (shim & co) guarantees the suicide in case of failure. So whether the false branch isn't hit doesn't make a difference.
But I wonder if, at this point, there is some other subtlety I'm not thinking about that could still bite us :-/
  
Cc: primiano@chromium.org

Comment 19 by siggi@chromium.org, Jan 16 2017

Would a base::debug::Alias(ptr) maybe persuade the compiler that the malloc can't be elided?
Ah didn't thought to that but if it works that would IMHO be a great alternative, significantly more elegant than my horrendous hack.
Blocking: 681800

Comment 22 by wfh@chromium.org, Jan 17 2017

Labels: -Needs-Bisect
Owner: wfh@chromium.org
Status: Started (was: Untriaged)
I'll try a few of the suggested tricks and see what works.

Comment 23 by r...@chromium.org, Jan 17 2017

Cc: r...@chromium.org
Project Member

Comment 24 by bugdroid1@chromium.org, Feb 13 2017

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/3dcb0a73e6f194be62930e7e1924a0b6965f5637

commit 3dcb0a73e6f194be62930e7e1924a0b6965f5637
Author: wfh <wfh@chromium.org>
Date: Mon Feb 13 20:53:00 2017

Fix ExhaustMemory on clang.

Also, bolster the current tests to verify sad tab behavior.

BUG= 681218 

Review-Url: https://codereview.chromium.org/2648423006
Cr-Commit-Position: refs/heads/master@{#450078}

[modify] https://crrev.com/3dcb0a73e6f194be62930e7e1924a0b6965f5637/chrome/browser/metrics/metrics_service_browsertest.cc
[modify] https://crrev.com/3dcb0a73e6f194be62930e7e1924a0b6965f5637/content/renderer/render_frame_impl.cc

Status: Fixed (was: Started)
I think Will fixed this.

Sign in to add a comment