Closed Bug 383426 Opened 17 years ago Closed 17 years ago

document.normalize() crash in OOM situation

Categories

(Core :: DOM: Core & HTML, defect)

x86
macOS
defect
Not set
critical

Tracking

()

RESOLVED FIXED

People

(Reporter: jruderman, Assigned: jruderman)

Details

(Keywords: crash, testcase, Whiteboard: [sg:critical])

Attachments

(3 files, 3 obsolete files)

Steps to reproduce:
1. Load the testcase, preferably in a build that you're running from a terminal window.
2. Wait 20s for it to load.
3. Wait 100s for it to use 4G of virtual memory.  (Watch it in Activity Monitor and/or watch for console output from malloc.)
4. Click the button.

Result: Crash in which pointers have been overwritten by bytes from UTF-16 text.

(gdb) bt
#0  0x45603003 in ?? ()
#1  0x18085ece in nsGenericElement::JoinTextNodes (this=0x410041, aFirst=0x410041, aSecond=0x410041) at /Users/jruderman/trunk/mozilla/content/base/src/nsGenericElement.cpp:1748
#2  0x00410041 in dyld_stub_fflush ()
Previous frame inner to this frame (corrupt stack?)

I hit this crash while trying to reproduce bug 374244.
I think the problem is that AppendASCIItoUTF16 doesn't check the return value of aDest.SetLength.  The stack is intact just before the call to copy_string, but once that call finishes, the stack is corrupted.

http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/xpcom/string/src/nsReadableUtils.cpp&rev=1.68&mark=137,149#137
Whiteboard: [sg:critical]
Attached patch patch to AppendASCIItoUTF16 (obsolete) — Splinter Review
This fixes the crash during normalize() for me.  I get a crash later (in layout rather than DOM), due to the "new" operator thinking it should throw rather than return null, but that's much better than a corrupted stack :)

If this is the right approach, I can write a patch that does the same thing to all the "Append" functions in nsReadableUtils.cpp.
You could use GetMutableData (see also bug 335957).
Flags: blocking1.9?
The GetMutableData interface confuses me.  Does the fact that it returns a length rather than a pointer mean I'm supposed to check that the returned length is correct?  If newLen is 0, how am I supposed to use the return value?
Can't you just return if the length you want is bigger than what GetMutableData returns? That should be able to deal with 0.
Assignee: nobody → jruderman
Flags: blocking1.9? → blocking1.9+
Jesse, are you going to revise your patch or do you want me to take it over?
I can revise it in a few days, but it would be great if you'd take it over.
Like this?

This patch has the same effect for me as the last one (no crash during normalize(), safe crash much later).
Attachment #267394 - Attachment is obsolete: true
That looks good to me, although I'd fuse these into one statement:

+    PRUint32 actual_new_dest_length;
+
+    actual_new_dest_length = aDest.GetMutableData(&dummy, new_dest_length);
Ok.  I initially had those as separate lines to avoid an 85-character line, but now I see that 90-character lines are not unusual in this file.
Please tick to 80 columns, but you could do:

PRUint32 actual_new_dest_length
  = aDest.GetMutableData(&dummy, new_dest_length);
Should I make a patch that does the same thing to all the Append conversion functions?
This introduces a "SetLengthForWriting" function so I don't have to include a bunch of redundant code in each Append* function.
Attachment #268603 - Attachment is obsolete: true
Attachment #268904 - Flags: superreview?(roc)
Attachment #268904 - Flags: review?(peterv)
Comment on attachment 268904 [details] [diff] [review]
patch to fix all uses of SetLength in nsReadableUtils.cpp

+bool

PRBool

+    if (!SetLengthForWritingC(aDest, old_dest_length + aSource.Length()))
+      {
+        return;
+      }

Better to just write:

+    if (!SetLengthForWritingC(aDest, old_dest_length + aSource.Length()))
+        return;
Attachment #268904 - Flags: superreview?(roc) → superreview+
Comment on attachment 268904 [details] [diff] [review]
patch to fix all uses of SetLength in nsReadableUtils.cpp

Ideally we'd also use the pointer returned by GetMutableData instead of using iterators, but let's just fix the crash first.
Attachment #268904 - Flags: review?(peterv) → review+
Attachment #268904 - Attachment is obsolete: true
Fixed on trunk.  This testcase is way too slow for an automated test.  Using ulimit (Linux only?) could make it faster, or maybe we could make a C++ test file that uses the string classes directly.
Status: NEW → RESOLVED
Closed: 17 years ago
Flags: in-testsuite?
Resolution: --- → FIXED
Loading the testcase and waiting 10 minutes makes my branch build abort:

firefox-bin(5906,0xa000d000) malloc: *** vm_allocate(size=33558528) failed (error code=3)
firefox-bin(5906,0xa000d000) malloc: *** error: can't allocate region
firefox-bin(5906,0xa000d000) malloc: *** set a breakpoint in szone_error to debug
terminate called after throwing an instance of 'std::bad_alloc'
  what():  St9bad_alloc

That makes it hard to use the testcase to determine whether branch has the memory safety bug, since I don't get a chance to click the normalize button.
Group: core-security
Component: DOM → DOM: Core & HTML
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: