FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-151022: Fix remote debugging linetable reads by goutamadwant · Pull Request #151036 · python/cpython · GitHub

Repository navigation

gh-151022: Fix remote debugging linetable reads - #151036

Merged
pablogsal merged 4 commits into
python:mainfrom
goutamadwant:gh-151022-remote-debugging-linetable
Jul 19, 2026
Merged

pablogsal merged 4 commits into
python:mainfrom
goutamadwant:gh-151022-remote-debugging-linetable

Conversation

Copy link
Copy Markdown
Contributor

Fixes gh-151022.

_remote_debugging reads a code object's line table from the target process
with a fixed 4096 byte limit. Valid code objects can exceed that. For example,
Lib/html/entities.py currently compiles to a line table of 37445 bytes, so
RemoteUnwinder.get_stack_trace() fails with RuntimeError: Invalid bytes length.

This keeps the generic remote bytes reader bounded, but gives code object line
tables their own larger limit before parsing. The parser already bounds the
number of line table entries it will scan.

Added a regression test that builds a code object with a line table larger than
4096 bytes and verifies that a same-process stack trace succeeds.

Tests:

./python.exe -m unittest -v test.test_external_inspection.TestSelfStackTrace.test_self_trace_with_large_linetable
./python.exe -m test test_external_inspection -v
make patchcheck

goutamadwant requested a review from pablogsal as a code owner June 6, 2026 22:13

python-cla-bot Bot commented Jun 6, 2026 •
edited
Loading

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

goutamadwant force-pushed the gh-151022-remote-debugging-linetable branch from 34645da to 9b0f3ba Compare June 6, 2026 22:19

Copy link
Copy Markdown
Member

@maurycy can you review this? :)

maurycy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@goutamadwant Woah! Thank you for jumping so quickly into this, and sorry for me jumping so slowly. :-) I've left some comments, with a small question mark to @pablogsal himself

# ============================================================================


class TestSelfStackTrace(RemoteInspectionTestBase):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@goutamadwant I think there's a missing @requires_remote_subprocess_debugging() decorator :-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Fixed @maurycy.. added the missing @requires_remote_subprocess_debugging() decorator to the new test class.

Comment on lines +470 to +472
self.assertEqual(
result.returncode, 0,
f"stdout: {result.stdout}\nstderr: {result.stderr}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@goutamadwant It would be interesting to ensure that the returned linetable is also correct, not -1 :-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@maurycy Updated this too. The test now checks the returned frame for large_linetable.py and asserts the resolved line number matches the generated RemoteUnwinder call line, so it should catch the -1 fallback case.


#include "_remote_debugging.h"

#define MAX_LINETABLE_SIZE (1024 * 1024)

maurycy Jun 9, 2026 •
edited
Loading

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@goutamadwant Why exactly 1024 * 1024? :-)

I know that's an arbitrary number but my hunch would be to try to check what sizes are we seeing in the wild, or at least in the stdlib. There's linetable_dist.py script in the original issue that should be helpful after a small modification!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

You are right @maurycy :) .. 1024 * 1024 was a conservative cap but not really data driven.

I ran a modified linetable scan against Lib. On current main I see max linetable size 37416 bytes, and the reported copyparty case was also lower, around 19536 bytes.

So I think 64 * 1024 may be a better cap for this PR. It covers the stdlib cases and the reported third party case, while still keeping the remote bytes read bounded much tighter than 1 MiB.

Does that sound reasonable to you ? I can make a change accordingly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

64 KiB sounds reasonable to me given the stdlib and reported third-party numbers.

#include "_remote_debugging.h"

#define MAX_LINETABLE_SIZE (1024 * 1024)
#define MAX_LINETABLE_ENTRIES 65536

maurycy Jun 9, 2026 •
edited
Loading

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@goutamadwant

I did not check it but my guess would be that there's much more head room in the MAX_LINETABLE_SIZE now, than in MAX_LINETABLE_ENTRIES. If I'm reading the code right, it fallbacks to -1:

if (!ok) {
info.lineno = -1;
info.end_lineno = -1;
info.column = -1;
info.end_column = -1;
}

@pablogsal

To be honest, I'd assert (proportionally) entries > size or get rid of MAX_LINETABLE_ENTRIES and entry_count. Either one depends on another, or one has to go...

Another solution would be along the lines of code_units (in CachedCodeMetadata?) but I think it's beyond the scope, and we still have to maintain some cap

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@maurycy I agree this needs a bit more thought.

From the same scan, the largest stdlib linetable I saw was Lib/html/entities.py with 37416 bytes and about 7465 parsed entries. So for the reported cases, the byte cap is the immediate problem. MAX_LINETABLE_ENTRIES still has enough headroom there.

my thinking is to keep the entry cap as a guard for malformed or pathological linetables and keep this PR focused on the too small byte read limit... I also strengthened the test so it checks a real line number instead of allowing -1.

Changing parse failure from unknown line to an exception feels like a separate behavior change to me. Happy to adjust if you and @pablogsal prefer that in this PR :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Agreed. With the 64 KiB cap, the separate entry limit is redundant because every iteration consumes at least one byte. Removing it is the cleanest option.

I would keep this PR focused on the read limit. We should open a follow-up to preserve the frame with an unknown location when line metadata cannot be read.

pablogsal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

LGTM

Let's land this focused fix and open a follow-up for graceful degradation. If line metadata exceeds the limit or cannot be read, we should preserve the frame with an unknown location instead of dropping the stack.

Thanks a lot for the fix!

pablogsal merged commit aeedae8 into python:main Jul 19, 2026
58 checks passed

Copy link
Copy Markdown

Thanks @goutamadwant for the PR, and @pablogsal for merging it 🌮🎉.. I'm working now to backport this PR to: 3.15.
🐍🍒⛏🤖

bedevere-app Bot commented Jul 19, 2026

Copy link
Copy Markdown

GH-154187 is a backport of this pull request to the 3.15 branch.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

_remote_debugging: raising Invalid bytes length on codeobjects with linetable > 4096

3 participants


Back | FazBrowse Home | New Git URL