fix: guard against undefined contexts (#9826)

We do not create contexts when we are unable to attribute them to a frame or they come from a stale oopif.
Async hop in the binding method can also cause the context to be destroyed already.

Reproduced with codegen.
This commit is contained in:
Dmitry Gozman 2021-10-27 13:28:52 -07:00 committed by GitHub
parent be64b5f6e2
commit 4743036bbe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 17 deletions

View file

@ -773,7 +773,9 @@ class FrameSession {
// @see https://github.com/GoogleChrome/puppeteer/issues/3865 // @see https://github.com/GoogleChrome/puppeteer/issues/3865
return; return;
} }
const context = this._contextIdToContext.get(event.executionContextId)!; const context = this._contextIdToContext.get(event.executionContextId);
if (!context)
return;
const values = event.args.map(arg => context.createHandle(arg)); const values = event.args.map(arg => context.createHandle(arg));
this._page._addConsoleMessage(event.type, values, toConsoleMessageLocation(event.stackTrace)); this._page._addConsoleMessage(event.type, values, toConsoleMessageLocation(event.stackTrace));
} }
@ -786,10 +788,12 @@ class FrameSession {
} }
async _onBindingCalled(event: Protocol.Runtime.bindingCalledPayload) { async _onBindingCalled(event: Protocol.Runtime.bindingCalledPayload) {
const context = this._contextIdToContext.get(event.executionContextId)!;
const pageOrError = await this._crPage.pageOrError(); const pageOrError = await this._crPage.pageOrError();
if (!(pageOrError instanceof Error)) if (!(pageOrError instanceof Error)) {
await this._page._onBindingCalled(event.payload, context); const context = this._contextIdToContext.get(event.executionContextId);
if (context)
await this._page._onBindingCalled(event.payload, context);
}
} }
_onDialog(event: Protocol.Page.javascriptDialogOpeningPayload) { _onDialog(event: Protocol.Page.javascriptDialogOpeningPayload) {

View file

@ -237,7 +237,9 @@ export class FFPage implements PageDelegate {
_onConsole(payload: Protocol.Runtime.consolePayload) { _onConsole(payload: Protocol.Runtime.consolePayload) {
const { type, args, executionContextId, location } = payload; const { type, args, executionContextId, location } = payload;
const context = this._contextIdToContext.get(executionContextId)!; const context = this._contextIdToContext.get(executionContextId);
if (!context)
return;
this._page._addConsoleMessage(type, args.map(arg => context.createHandle(arg)), location); this._page._addConsoleMessage(type, args.map(arg => context.createHandle(arg)), location);
} }
@ -253,15 +255,19 @@ export class FFPage implements PageDelegate {
} }
async _onBindingCalled(event: Protocol.Page.bindingCalledPayload) { async _onBindingCalled(event: Protocol.Page.bindingCalledPayload) {
const context = this._contextIdToContext.get(event.executionContextId)!;
const pageOrError = await this.pageOrError(); const pageOrError = await this.pageOrError();
if (!(pageOrError instanceof Error)) if (!(pageOrError instanceof Error)) {
await this._page._onBindingCalled(event.payload, context); const context = this._contextIdToContext.get(event.executionContextId);
if (context)
await this._page._onBindingCalled(event.payload, context);
}
} }
async _onFileChooserOpened(payload: Protocol.Page.fileChooserOpenedPayload) { async _onFileChooserOpened(payload: Protocol.Page.fileChooserOpenedPayload) {
const { executionContextId, element } = payload; const { executionContextId, element } = payload;
const context = this._contextIdToContext.get(executionContextId)!; const context = this._contextIdToContext.get(executionContextId);
if (!context)
return;
const handle = context.createHandle(element).asElement()!; const handle = context.createHandle(element).asElement()!;
await this._page._onFileChooserOpened(handle); await this._page._onFileChooserOpened(handle);
} }

View file

@ -498,9 +498,9 @@ export class WKPage implements PageDelegate {
const { type, level, text, parameters, url, line: lineNumber, column: columnNumber, source } = event.message; const { type, level, text, parameters, url, line: lineNumber, column: columnNumber, source } = event.message;
if (level === 'debug' && parameters && parameters[0].value === BINDING_CALL_MESSAGE) { if (level === 'debug' && parameters && parameters[0].value === BINDING_CALL_MESSAGE) {
const parsedObjectId = JSON.parse(parameters[1].objectId!); const parsedObjectId = JSON.parse(parameters[1].objectId!);
const context = this._contextIdToContext.get(parsedObjectId.injectedScriptId)!;
this.pageOrError().then(pageOrError => { this.pageOrError().then(pageOrError => {
if (!(pageOrError instanceof Error)) const context = this._contextIdToContext.get(parsedObjectId.injectedScriptId);
if (!(pageOrError instanceof Error) && context)
this._page._onBindingCalled(parameters[2].value, context); this._page._onBindingCalled(parameters[2].value, context);
}); });
return; return;
@ -531,16 +531,19 @@ export class WKPage implements PageDelegate {
else if (type === 'timing') else if (type === 'timing')
derivedType = 'timeEnd'; derivedType = 'timeEnd';
const handles = (parameters || []).map(p => { const handles: JSHandle[] = [];
let context: dom.FrameExecutionContext | null = null; for (const p of parameters || []) {
let context: dom.FrameExecutionContext | undefined;
if (p.objectId) { if (p.objectId) {
const objectId = JSON.parse(p.objectId); const objectId = JSON.parse(p.objectId);
context = this._contextIdToContext.get(objectId.injectedScriptId)!; context = this._contextIdToContext.get(objectId.injectedScriptId);
} else { } else {
context = this._contextIdToContext.get(this._mainFrameContextId!)!; context = this._contextIdToContext.get(this._mainFrameContextId!);
} }
return context.createHandle(p); if (!context)
}); return;
handles.push(context.createHandle(p));
}
this._lastConsoleMessage = { this._lastConsoleMessage = {
derivedType, derivedType,
text, text,