Closed
Bug 321487
Opened 19 years ago
Closed 19 years ago
Crash when moving caret backwards over text frame consisting of a single CR [nsTextFrame::PeekOffset]
Categories
(Core :: Layout: Text and Fonts, defect)
Core
Layout: Text and Fonts
Tracking
()
VERIFIED
FIXED
mozilla1.8.1
People
(Reporter: uriber, Assigned: uriber)
References
Details
(4 keywords)
Attachments
(3 files, 1 obsolete file)
354 bytes,
text/html
|
Details | |
67 bytes,
text/html
|
Details | |
1.26 KB,
patch
|
rbs
:
review+
bzbarsky
:
superreview+
dveditz
:
approval1.8.0.1+
dveditz
:
approval1.8.1+
|
Details | Diff | Splinter Review |
This is a followup on bug 319705 (see bug 319705 comment #9, 2nd paragraph). If, using script, you create a DOM text node consisting of a single CR (0x0d), moving the caret backwords over this text crashes the browser (at least on OS X. Since this is a case of uninitialized memory used as an array subscript, other OSs might not crash). I'll attach a testcase immediately. Here's my analysis of the problem (based bug 319705 comment #6 and #7): What happens is that PrepareUnicodeText() in this case leaves indexBuffer.mBuffer uninitialized (the single character in the content is not mapped to anything). Later, when nsTextFrame::PeekOffset() examines ip[i] (which is really indexBuffer.mBuffer[0]), it finds junk there, and from there on all kinds of things can happen. The reason PrepareUnicodeText() does not init indexBuffer.mBuffer[0] is that the call to aTX.GetNextWord() returns nsnull, which then causes an immediate break out of the loop. I can't say whether GetNextWord() really should return nsnull in this case (and then it should just be handled better by PrepareUnicodeText()), or whether the problem is in GetNextWord() itself.
Assignee | ||
Comment 1•19 years ago
|
||
Load the testcase in the browser, then: - Turn on caret browsing mode (F7) - Place the caret in the word "World" - Use left-arrow to move into the word "Hello" You should crash as you try to move over the (invisible) CR between the two words. The crash is in the following line: if ((ip[i] < ip[aPos->mStartOffset - mContentOffset]) && (clusterBuffer.mBuffer[ip[i] - mContentOffset]) && (! IS_LOW_SURROGATE(paintBuffer.mBuffer[ip[i]-mContentOffset]))) i=0. ip[0] is junk, so what actually crashes is probably |clusterBuffer.mBuffer[ip[i] - mContentOffset]|
Assignee | ||
Comment 2•19 years ago
|
||
All/All because the underlying problem is clearly cross-platform (regardless whether other platforms actually crash).
Comment 3•19 years ago
|
||
Is this the sort of thing that could cause jumps into random memory? Or just reads of random memory?
Flags: blocking1.9a1+
Assignee | ||
Comment 4•19 years ago
|
||
(In reply to comment #3) > Is this the sort of thing that could cause jumps into random memory? Or just > reads of random memory? It seems to me that this can not cause random-memory jumps, only reads. BTW, I had a chance to test the attached testcase on Windows, and it did not crash (not that this matters much).
Comment 5•19 years ago
|
||
So which case do we end up hitting in PrepareUnicodeText? Do we get isWhitespace equal to true? Or no?
Assignee | ||
Comment 6•19 years ago
|
||
(In reply to comment #5) > So which case do we end up hitting in PrepareUnicodeText? Do we get > isWhitespace equal to true? Or no? No, isWhitespace is false - but we never get to the point where we ask about it. We get into |if (nsnull == bp)| (line 2118), and thus break out of the loop (line 2227). From there on, nothing sets aIndexBuffer.mBuffer[0]. Note that empirically this appears to be a regression: I'm not crashing with builds from 2005-04-30 and before (first crashing build that I found so far is 2005-05-03).
Comment 7•19 years ago
|
||
Hmm. Does GetNextWord() return non-null for a single space, say?
Assignee | ||
Comment 8•19 years ago
|
||
(In reply to comment #7) > Hmm. Does GetNextWord() return non-null for a single space, say? Yes, it returns a non-null for a single space.
Assignee | ||
Comment 9•19 years ago
|
||
What causes \r to behave differently (than e.g. a space) in nsTextTransformer::GetNextWord() is that it's explicitly specified in the IS_DISCARDED macro. This is also true for ­ - this testcase demonstartes the same crash, with ­ which does not require script to be inserted. Instructions for crashing are as in the previous testcase.
Comment 10•19 years ago
|
||
OK. And the same would happen with BiDi control chars. So what do we need to do in PrepareUnicodeDimensions to deal with a sequence of discarded chars and nothing else? rbs, any ideas?
Assignee | ||
Comment 11•19 years ago
|
||
Apparently, there is already a solution (or at least a "solution") for this in the bidi case. So here I'm just adopting that solution for the general case. This does fix my two testcases, but I don't really know the code well enough to explain why initializing the index buffer this way is (or isn't) correct (or even acceptable) in this case.
Attachment #206812 -
Flags: superreview?(bzbarsky)
Attachment #206812 -
Flags: review?
Assignee | ||
Updated•19 years ago
|
Attachment #206812 -
Flags: review? → review?(rbs)
Comment 12•19 years ago
|
||
(In reply to comment #9) > Created an attachment (id=206805) [edit] > testcase using ­ Probably related: bug 319914.
Summary: Crash when moving caret backwards over text frame consisting of a single CR → Crash when moving caret backwards over text frame consisting of a single CR [nsTextFrame::PeekOffset]
Comment 13•19 years ago
|
||
Yeah that patch fixes the ­ issue from Bug 319914. Note pasting ­ (and moving cursor over it in a debug build) actually worked once (meaning did not crash), this has regressed in 2004, for some rough regression range see the Bug.
Assignee | ||
Comment 14•19 years ago
|
||
Notice bug 244876 which would explain why this did not crash before 2004-05-31 (but not why it started crashing only about a year later). It's possible that whoever wrote this code actually relied on newly-initialized buffers to be zero-filled (as they were before bug 244876 was fixed).
Comment 15•19 years ago
|
||
Do we want this on branches? Seems like we would...
Flags: blocking1.8.1?
Flags: blocking1.8.0.1?
Comment 16•19 years ago
|
||
Comment on attachment 206812 [details] [diff] [review] patch? Looks reasonable.
Attachment #206812 -
Flags: superreview?(bzbarsky) → superreview+
Comment 17•19 years ago
|
||
-#ifdef IBMBIDI - if (indexp && (mState & NS_FRAME_IS_BIDI) ) { + if (indexp) { while (--n >= 0) { *indexp++ = strInx++; } } -#endif // IBMBIDI I wonder why Bidi is doing what it is doing. For normal cases, it seems to me that strInx shouldn't be incremented because it is a bit at odd with the spirit of that code. For future refences, here is what that code is doing. Assume for simplicity mContentOffset = 0, and suppose the corresponding DOM content of the nsTextFrame has these four characters: 0 1 2 3 4 mContentLength = 5 a|ß|­|­|b Now, assume that it has the CSS "text-transform: uppercase". Hence the German ß "expands" to SS and ­ "shrinks" to nothing. PrepareUnicodeText is meant to deal with both situations: expansion and contraction. In the example, the prepared output becomes: 0 12 3 <--- textlength = 4 A|SS|B What PrepareUnicodeText does is to encode this transformation. To do so, indexp will run up to mContentLength and record the _beginning_ of the mapped "segment" correspond to each DOM character. Thus: indexp[]: runs from 0 to 5, and maps a|ß|­|­|b 0| 1 | 2 | 3 |4|5 <--- this is indexp ^ extra to: 0| 1 | 3 | 3 |3|4 <--- this is strInx ^ textlength In other words, the i-th DOM character is representable with the peparedText[ indexp[i] : indexp[i + 1] - 1 ]. You can see how the extra is set from this last bit of code: if (aIndexBuffer) { PRInt32* ip = aIndexBuffer->mBuffer; ip[mContentLength] = ip[mContentLength-1]; if ((ip[mContentLength] - mContentOffset) < textLength) { // Must set up last one for selection beyond edge if in boundary ip[mContentLength] = textLength + mContentOffset; } } Note how it does not increment ip[mContentLength] if the content has indeed collapsed to nothingness. Given that the spirit of the code is to map the i-th DOM character to the corresponding peparedText[ indexp[i] ... indexp[i + 1] - 1 ], incrementing is creating fictional (unset) references. Can you just try: + if (indexp) { while (--n >= 0) { - *indexp++ = strInx++; *indexp++ = strInx; } }
Assignee | ||
Comment 18•19 years ago
|
||
Yes, this works as well, and makes more sense. Thanks for the explanation in comment #17 - I now understand this better.
Assignee: nobody → uriber
Attachment #206812 -
Attachment is obsolete: true
Status: NEW → ASSIGNED
Attachment #206907 -
Flags: superreview?(bzbarsky)
Attachment #206907 -
Flags: review?(rbs)
Attachment #206812 -
Flags: review?(rbs)
Comment 19•19 years ago
|
||
Comment on attachment 206907 [details] [diff] [review] patch v2 r=rbs
Attachment #206907 -
Flags: review?(rbs) → review+
Updated•19 years ago
|
Attachment #206907 -
Flags: superreview?(bzbarsky) → superreview+
Assignee | ||
Comment 20•19 years ago
|
||
Patch checked in, 2005-12-27 07:15.
Status: ASSIGNED → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
Comment 21•19 years ago
|
||
Comment on attachment 206907 [details] [diff] [review] patch v2 a=dveditz for drivers
Attachment #206907 -
Flags: approval1.8.1+
Attachment #206907 -
Flags: approval1.8.0.1+
Updated•19 years ago
|
Flags: blocking1.8.1?
Flags: blocking1.8.1+
Flags: blocking1.8.0.1?
Flags: blocking1.8.0.1+
Assignee | ||
Comment 22•19 years ago
|
||
Checked in to 1.8 and 1.8.0 branches: Checking in layout/generic/nsTextFrame.cpp; /cvsroot/mozilla/layout/generic/nsTextFrame.cpp,v <-- nsTextFrame.cpp new revision: 1.513.4.7; previous revision: 1.513.4.6 done Checking in layout/generic/nsTextFrame.cpp; /cvsroot/mozilla/layout/generic/nsTextFrame.cpp,v <-- nsTextFrame.cpp new revision: 1.513.4.6.2.1; previous revision: 1.513.4.6 done
Target Milestone: --- → mozilla1.8.1
Assignee | ||
Updated•19 years ago
|
Keywords: fixed1.8.0.1,
fixed1.8.1
Comment 23•19 years ago
|
||
v.fixed on 1.8.0.1 with Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.1) Gecko/20060109 Firefox/1.5.0.1, no crash with uri's testcase.
Updated•19 years ago
|
Status: RESOLVED → VERIFIED
Keywords: verified1.8.0.1
Updated•19 years ago
|
Keywords: fixed1.8.0.1
You need to log in
before you can comment on or make changes to this bug.
Description
•