Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Evaluate may hang if frame changes to OOPIF #10715

Closed
1 of 2 tasks
liamdalg opened this issue Aug 9, 2023 · 4 comments
Closed
1 of 2 tasks

[Bug]: Evaluate may hang if frame changes to OOPIF #10715

liamdalg opened this issue Aug 9, 2023 · 4 comments
Assignees

Comments

@liamdalg
Copy link

liamdalg commented Aug 9, 2023

Minimal, reproducible example

import puppeteer from 'puppeteer';

const OOPIF_BASE = 'http://127.0.0.1:8000';
const BASE = 'http://localhost:8000';

const sleep = t => new Promise(r => setTimeout(r, t));

const browser = await puppeteer.launch({
    headless: 'new',
});

const page = await browser.newPage();
await page.goto(`${BASE}/iframe.html`);

for (const f of page.frames()) {
    console.log(`Evaluating in ${f._id}, ${f.url()}, ${f.isOOPFrame()}`);
    await f.evaluate(() => 1 + 1);
    console.log('Done');
}

await page.$eval('iframe', (f, b) => f.setAttribute('src', `${b}/blank.html`), OOPIF_BASE);

for (const f of page.frames()) {
    console.log(`Evaluating in ${f._id}, ${f.url()}, ${f.isOOPFrame()}`);
    await f.evaluate(() => 1 + 1);
    console.log('Done');
}

await browser.close();

Error string

no error

Bug behavior

  • Flaky
  • PDF

Background

In new headless, if a call to frame.evaluate races against the frame changing from a normal iframe to an OOPIF, then it may hang. The minimal example attached requires the two attached files to be available at localhost:8000; I've been running it with python3 -m http.server. Note that this is quite flaky given it's a race condition. On my machine it triggers a hang around 20% of the time.

HTML Files
oopif.log

Possibly related to my other bug report #10696.

For now, I've been avoiding this by running with --disable-features=SitePerProcess.

Expectation

Either:

  • Evaluation to succeed, or
  • Error: Execution context was destroyed, most likely because of a navigation to be thrown.

Reality

frame.evaluate hangs indefinitely.

Puppeteer configuration file (if used)

No response

Puppeteer version

21.0.2

Node version

18.16.1

Package manager

npm

Package manager version

9.5.1

Operating system

Windows

@liamdalg liamdalg added the bug label Aug 9, 2023
@github-actions
Copy link

github-actions bot commented Aug 9, 2023

The issue has been labeled as confirmed by the automatic analyser.
Someone from the Puppeteer team will take a look soon!


Analyzer run

@github-actions github-actions bot added confirmed and removed invalid labels Aug 9, 2023
@OrKoN
Copy link
Collaborator

OrKoN commented Aug 10, 2023

Looks like there is a race condition here because iframe navigation is asynchronous. We should at least error here.

Adding await page.waitForFrame(frame => frame.isOOPFrame()) after await page.$eval('iframe', (f, b) => f.setAttribute('src', ${b}/blank.html), OOPIF_BASE); makes it more robust (it seems).

@OrKoN OrKoN added the P2 label May 2, 2024
@OrKoN OrKoN self-assigned this May 7, 2024
@OrKoN
Copy link
Collaborator

OrKoN commented May 7, 2024

@liamdalg are you still able to reproduce the issue using the latest version?

I am not seeing any flakiness in a thousand runs:

import puppeteer from 'puppeteer';

const OOPIF_BASE = 'http://127.0.0.1:8000';
const BASE = 'http://localhost:8000';

const sleep = t => new Promise(r => setTimeout(r, t));

const browser = await puppeteer.launch({
  headless: 'new',
});

for (let i = 0; i < 1000; i++) {
  const page = await browser.newPage();
  await page.goto(`${BASE}/iframe.html`);

  for (const f of page.frames()) {
    console.log(`Evaluating in ${f._id}, ${f.url()}, ${f.isOOPFrame()}`);
    await f.evaluate(() => 1 + 1);
    console.log('Done');
  }

  await Promise.all([
    page.$eval('iframe', (f, b) => f.setAttribute('src', `${b}/blank.html`), OOPIF_BASE),
  ]);

  await page.waitForFrame(frame => frame.isOOPFrame())

  for (const f of page.frames()) {
    console.log(`Evaluating in ${f._id}, ${f.url()}, ${f.isOOPFrame()}`);
    await f.evaluate(() => 1 + 1);
    console.log('Done');
  }

  await page.close()
}
await browser.close();

@liamdalg
Copy link
Author

liamdalg commented May 7, 2024

Looks like its fixed on my end too. It no longer hangs as of v21.7.0 - it either succeeds or exits with Execution context was destroyed!. Thanks!

@OrKoN OrKoN closed this as completed May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants