1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
|
commit 7efadbb03cdffa11ebfc2da3113377d2f33b893b
Author: Henri Sivonen <hsivonen@hsivonen.fi>
Date: Mon Nov 3 15:23:26 2014 +0200
Bug 1088635. r=smaug, a=bkerensa
Modified content/base/src/nsDocument.cpp
diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp
index cbed38d..3493bce 100644
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -3916,7 +3916,7 @@ nsDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify)
{
if (aKid->IsElement() && GetRootElement()) {
- NS_ERROR("Inserting element child when we already have one");
+ NS_WARNING("Inserting root element when we already have one");
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
Modified parser/html/nsHtml5Parser.cpp
diff --git a/parser/html/nsHtml5Parser.cpp b/parser/html/nsHtml5Parser.cpp
index a485be4..f28adb4 100644
--- a/parser/html/nsHtml5Parser.cpp
+++ b/parser/html/nsHtml5Parser.cpp
@@ -237,7 +237,8 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
* WillBuildModel to be called before the document has had its
* script global object set.
*/
- mExecutor->WillBuildModel(eDTDMode_unknown);
+ rv = mExecutor->WillBuildModel(eDTDMode_unknown);
+ NS_ENSURE_SUCCESS(rv, rv);
}
// Return early if the parser has processed EOF
@@ -255,7 +256,7 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
}
mDocumentClosed = true;
if (!mBlocked && !mInDocumentWrite) {
- ParseUntilBlocked();
+ return ParseUntilBlocked();
}
return NS_OK;
}
@@ -378,7 +379,8 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
if (mTreeBuilder->HasScript()) {
mTreeBuilder->Flush(); // Move ops to the executor
- mExecutor->FlushDocumentWrite(); // run the ops
+ rv = mExecutor->FlushDocumentWrite(); // run the ops
+ NS_ENSURE_SUCCESS(rv, rv);
// Flushing tree ops can cause all sorts of things.
// Return early if the parser got terminated.
if (mExecutor->IsComplete()) {
@@ -437,7 +439,8 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
"Buffer wasn't tokenized to completion?");
// Scripting semantics require a forced tree builder flush here
mTreeBuilder->Flush(); // Move ops to the executor
- mExecutor->FlushDocumentWrite(); // run the ops
+ rv = mExecutor->FlushDocumentWrite(); // run the ops
+ NS_ENSURE_SUCCESS(rv, rv);
} else if (stackBuffer.hasMore()) {
// The buffer wasn't tokenized to completion. Tokenize the untokenized
// content in order to preload stuff. This content will be retokenized
@@ -594,11 +597,13 @@ nsHtml5Parser::IsScriptCreated()
/* End nsIParser */
// not from interface
-void
+nsresult
nsHtml5Parser::ParseUntilBlocked()
{
- if (mBlocked || mExecutor->IsComplete() || NS_FAILED(mExecutor->IsBroken())) {
- return;
+ nsresult rv = mExecutor->IsBroken();
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (mBlocked || mExecutor->IsComplete()) {
+ return NS_OK;
}
NS_ASSERTION(mExecutor->HasStarted(), "Bad life cycle.");
NS_ASSERTION(!mInDocumentWrite,
@@ -611,7 +616,7 @@ nsHtml5Parser::ParseUntilBlocked()
if (mFirstBuffer == mLastBuffer) {
if (mExecutor->IsComplete()) {
// something like cache manisfests stopped the parse in mid-flight
- return;
+ return NS_OK;
}
if (mDocumentClosed) {
NS_ASSERTION(!GetStreamParser(),
@@ -620,8 +625,10 @@ nsHtml5Parser::ParseUntilBlocked()
mTreeBuilder->StreamEnded();
mTreeBuilder->Flush();
mExecutor->FlushDocumentWrite();
+ // The below call does memory cleanup, so call it even if the
+ // parser has been marked as broken.
mTokenizer->end();
- return;
+ return NS_OK;
}
// never release the last buffer.
NS_ASSERTION(!mLastBuffer->getStart() && !mLastBuffer->getEnd(),
@@ -643,14 +650,14 @@ nsHtml5Parser::ParseUntilBlocked()
NS_ASSERTION(mExecutor->IsInFlushLoop(),
"How did we come here without being in the flush loop?");
}
- return; // no more data for now but expecting more
+ return NS_OK; // no more data for now but expecting more
}
mFirstBuffer = mFirstBuffer->next;
continue;
}
if (mBlocked || mExecutor->IsComplete()) {
- return;
+ return NS_OK;
}
// now we have a non-empty buffer
@@ -667,10 +674,11 @@ nsHtml5Parser::ParseUntilBlocked()
}
if (mTreeBuilder->HasScript()) {
mTreeBuilder->Flush();
- mExecutor->FlushDocumentWrite();
+ nsresult rv = mExecutor->FlushDocumentWrite();
+ NS_ENSURE_SUCCESS(rv, rv);
}
if (mBlocked) {
- return;
+ return NS_OK;
}
}
continue;
Modified parser/html/nsHtml5Parser.h
diff --git a/parser/html/nsHtml5Parser.h b/parser/html/nsHtml5Parser.h
index aff79c7..e2ef2f8 100644
--- a/parser/html/nsHtml5Parser.h
+++ b/parser/html/nsHtml5Parser.h
@@ -262,7 +262,7 @@ class nsHtml5Parser : public nsIParser,
/**
* Parse until pending data is exhausted or a script blocks the parser
*/
- void ParseUntilBlocked();
+ nsresult ParseUntilBlocked();
private:
Modified parser/html/nsHtml5StreamParser.cpp
diff --git a/parser/html/nsHtml5StreamParser.cpp b/parser/html/nsHtml5StreamParser.cpp
index 4790568..7e3917b 100644
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -796,7 +796,7 @@ nsHtml5StreamParser::WriteStreamBytes(const uint8_t* aFromSegment,
// NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE.
if (!mLastBuffer) {
NS_WARNING("mLastBuffer should not be null!");
- MarkAsBroken();
+ MarkAsBroken(NS_ERROR_NULL_POINTER);
return NS_ERROR_NULL_POINTER;
}
if (mLastBuffer->getEnd() == NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE) {
@@ -902,7 +902,8 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
* WillBuildModel to be called before the document has had its
* script global object set.
*/
- mExecutor->WillBuildModel(eDTDMode_unknown);
+ rv = mExecutor->WillBuildModel(eDTDMode_unknown);
+ NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsHtml5OwningUTF16Buffer> newBuf =
nsHtml5OwningUTF16Buffer::FalliblyCreate(
@@ -1003,8 +1004,9 @@ nsHtml5StreamParser::DoStopRequest()
if (!mUnicodeDecoder) {
uint32_t writeCount;
- if (NS_FAILED(FinalizeSniffing(nullptr, 0, &writeCount, 0))) {
- MarkAsBroken();
+ nsresult rv;
+ if (NS_FAILED(rv = FinalizeSniffing(nullptr, 0, &writeCount, 0))) {
+ MarkAsBroken(rv);
return;
}
} else if (mFeedChardet) {
@@ -1076,7 +1078,7 @@ nsHtml5StreamParser::DoDataAvailable(const uint8_t* aBuffer, uint32_t aLength)
rv = SniffStreamBytes(aBuffer, aLength, &writeCount);
}
if (NS_FAILED(rv)) {
- MarkAsBroken();
+ MarkAsBroken(rv);
return;
}
NS_ASSERTION(writeCount == aLength, "Wrong number of stream bytes written/sniffed.");
@@ -1662,13 +1664,13 @@ nsHtml5StreamParser::TimerFlush()
}
void
-nsHtml5StreamParser::MarkAsBroken()
+nsHtml5StreamParser::MarkAsBroken(nsresult aRv)
{
NS_ASSERTION(IsParserThread(), "Wrong thread!");
mTokenizerMutex.AssertCurrentThreadOwns();
Terminate();
- mTreeBuilder->MarkAsBroken();
+ mTreeBuilder->MarkAsBroken(aRv);
mozilla::DebugOnly<bool> hadOps = mTreeBuilder->Flush(false);
NS_ASSERTION(hadOps, "Should have had the markAsBroken op!");
if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
Modified parser/html/nsHtml5StreamParser.h
diff --git a/parser/html/nsHtml5StreamParser.h b/parser/html/nsHtml5StreamParser.h
index c7dcbbe..476ef16 100644
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -218,7 +218,7 @@ class nsHtml5StreamParser : public nsICharsetDetectionObserver {
}
#endif
- void MarkAsBroken();
+ void MarkAsBroken(nsresult aRv);
/**
* Marks the stream parser as interrupted. If you ever add calls to this
Modified parser/html/nsHtml5TreeBuilderCppSupplement.h
diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h
index 4cd5c7c..1e65394 100644
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -949,14 +949,14 @@ nsHtml5TreeBuilder::DropHandles()
}
void
-nsHtml5TreeBuilder::MarkAsBroken()
+nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv)
{
if (MOZ_UNLIKELY(mBuilder)) {
MOZ_ASSUME_UNREACHABLE("Must not call this with builder.");
return;
}
mOpQueue.Clear(); // Previous ops don't matter anymore
- mOpQueue.AppendElement()->Init(eTreeOpMarkAsBroken);
+ mOpQueue.AppendElement()->Init(aRv);
}
void
Modified parser/html/nsHtml5TreeBuilderHSupplement.h
diff --git a/parser/html/nsHtml5TreeBuilderHSupplement.h b/parser/html/nsHtml5TreeBuilderHSupplement.h
index a321e80..8d380eb 100644
--- a/parser/html/nsHtml5TreeBuilderHSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderHSupplement.h
@@ -223,4 +223,4 @@
void errEndWithUnclosedElements(nsIAtom* aName);
- void MarkAsBroken();
+ void MarkAsBroken(nsresult aRv);
Modified parser/html/nsHtml5TreeOpExecutor.cpp
diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp
index ebcafca..6c52e5f 100644
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -411,7 +411,11 @@ nsHtml5TreeOpExecutor::RunFlushLoop()
GetParser()->GetStreamParser();
// Now parse content left in the document.write() buffer queue if any.
// This may generate tree ops on its own or dequeue a speculation.
- GetParser()->ParseUntilBlocked();
+ nsresult rv = GetParser()->ParseUntilBlocked();
+ if (NS_FAILED(rv)) {
+ MarkAsBroken(rv);
+ return;
+ }
}
if (mOpQueue.IsEmpty()) {
@@ -496,21 +500,24 @@ nsHtml5TreeOpExecutor::RunFlushLoop()
}
}
-void
+nsresult
nsHtml5TreeOpExecutor::FlushDocumentWrite()
{
+ nsresult rv = IsBroken();
+ NS_ENSURE_SUCCESS(rv, rv);
+
FlushSpeculativeLoads(); // Make sure speculative loads never start after the
// corresponding normal loads for the same URLs.
if (MOZ_UNLIKELY(!mParser)) {
// The parse has ended.
mOpQueue.Clear(); // clear in order to be able to assert in destructor
- return;
+ return rv;
}
if (mFlushState != eNotFlushing) {
// XXX Can this happen? In case it can, let's avoid crashing.
- return;
+ return rv;
}
mFlushState = eInFlush;
@@ -545,7 +552,7 @@ nsHtml5TreeOpExecutor::FlushDocumentWrite()
}
NS_ASSERTION(mFlushState == eInDocUpdate,
"Tried to perform tree op outside update batch.");
- nsresult rv = iter->Perform(this, &scriptElement);
+ rv = iter->Perform(this, &scriptElement);
if (NS_FAILED(rv)) {
MarkAsBroken(rv);
break;
@@ -560,13 +567,14 @@ nsHtml5TreeOpExecutor::FlushDocumentWrite()
if (MOZ_UNLIKELY(!mParser)) {
// Ending the doc update caused a call to nsIParser::Terminate().
- return;
+ return rv;
}
if (scriptElement) {
// must be tail call when mFlushState is eNotFlushing
RunScript(scriptElement);
}
+ return rv;
}
// copied from HTML content sink
Modified parser/html/nsHtml5TreeOpExecutor.h
diff --git a/parser/html/nsHtml5TreeOpExecutor.h b/parser/html/nsHtml5TreeOpExecutor.h
index 9617dcb..1f81448 100644
--- a/parser/html/nsHtml5TreeOpExecutor.h
+++ b/parser/html/nsHtml5TreeOpExecutor.h
@@ -173,7 +173,7 @@ class nsHtml5TreeOpExecutor : public nsHtml5DocumentBuilder,
void RunFlushLoop();
- void FlushDocumentWrite();
+ nsresult FlushDocumentWrite();
void MaybeSuspend();
Modified parser/html/nsHtml5TreeOperation.cpp
diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp
index 48b71dc..7ad65247 100644
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -214,6 +214,9 @@ nsHtml5TreeOperation::AppendToDocument(nsIContent* aNode,
nsIDocument* doc = aBuilder->GetDocument();
uint32_t childCount = doc->GetChildCount();
rv = doc->AppendChildTo(aNode, false);
+ if (rv == NS_ERROR_DOM_HIERARCHY_REQUEST_ERR) {
+ return NS_OK;
+ }
NS_ENSURE_SUCCESS(rv, rv);
nsNodeUtils::ContentInserted(doc, aNode, childCount);
@@ -739,8 +742,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
return NS_OK;
}
case eTreeOpMarkAsBroken: {
- aBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
- return NS_OK;
+ return mOne.result;
}
case eTreeOpRunScript: {
nsIContent* node = *(mOne.node);
Modified parser/html/nsHtml5TreeOperation.h
diff --git a/parser/html/nsHtml5TreeOperation.h b/parser/html/nsHtml5TreeOperation.h
index 2727733..06d0274 100644
--- a/parser/html/nsHtml5TreeOperation.h
+++ b/parser/html/nsHtml5TreeOperation.h
@@ -435,6 +435,15 @@ class nsHtml5TreeOperation {
mFour.integer = aInt;
}
+ inline void Init(nsresult aRv)
+ {
+ NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
+ "Op code must be uninitialized when initializing.");
+ NS_PRECONDITION(NS_FAILED(aRv), "Initialized tree op with non-failure.");
+ mOpCode = eTreeOpMarkAsBroken;
+ mOne.result = aRv;
+ }
+
inline void InitAddClass(nsIContentHandle* aNode, const char16_t* aClass)
{
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
@@ -487,11 +496,12 @@ class nsHtml5TreeOperation {
nsIAtom* atom;
nsHtml5HtmlAttributes* attributes;
nsHtml5DocumentMode mode;
- char16_t* unicharPtr;
+ char16_t* unicharPtr;
char* charPtr;
nsHtml5TreeOperationStringPair* stringPair;
nsAHtml5TreeBuilderState* state;
int32_t integer;
+ nsresult result;
} mOne, mTwo, mThree, mFour;
};
|