Skip to content

gh-134876: Add fallback for when process_vm_readv fails with ENOSYS #134878

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

cakemanny
Copy link

@cakemanny cakemanny commented May 29, 2025

This adds a fallback /proc/[pid]/mem from the proc(5) filesystem when process_vm_readv and process_vm_writev are not compiled into the kernel.

Regarding tests, these are covered by ./python -m test --match 'test_remote_pdb', but only on affected systems.
Do say if this merits a NEWS entry, I wasn't sure because it's a fix for not yet released python versions.

@cakemanny cakemanny requested a review from pablogsal as a code owner May 29, 2025 10:57
@python-cla-bot
Copy link

python-cla-bot bot commented May 29, 2025

All commit authors signed the Contributor License Agreement.

CLA signed

@bedevere-app
Copy link

bedevere-app bot commented May 29, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@cakemanny
Copy link
Author

I think the those tests are only failing because compilation fails on gcc-10. I'll have a look and see if I can obtain a copy and will update accordingly.

@cakemanny cakemanny force-pushed the fallback-to-proc-mem branch from 938b91c to 90b08e6 Compare May 29, 2025 12:28
@bedevere-app
Copy link

bedevere-app bot commented May 29, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@@ -952,6 +955,38 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address
result += read_bytes;
} while ((size_t)read_bytes != local[0].iov_len);
return 0;
fallback:
; // statement after label needed by gcc 10 and earlier
Copy link
Member

Choose a reason for hiding this comment

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

Can you factor the fallback out into a different function. I think this makes the normal path more difficult to read

char mem_file_path[64];
off_t offset = 0;
sprintf(mem_file_path, "/proc/%d/mem", handle->pid);
int fd = open(mem_file_path, O_RDONLY);
Copy link
Member

Choose a reason for hiding this comment

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

This is going to be tremendously inefficient for a profiler because it keeps opening the pseudo file all the time

Copy link
Author

Choose a reason for hiding this comment

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

I could add the file descriptor to proc_handle_t with an initial value of -1 and then open only on the first ENOSYS. Any thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

You can guard it with macros for process_vm_readv but we are already checking for they to compile all of this in so you still need to deal with that problem

Copy link
Member

Choose a reason for hiding this comment

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

Ah no my bad. The problem here is that the function IS defined but the kernel refuses.... alright in that case yeah add it with a guard for only Linux


result += read_bytes;
} while ((size_t)read_bytes != local[0].iov_len);
close(fd);
Copy link
Member

Choose a reason for hiding this comment

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

Same as before

local[0].iov_len = len - result;
offset = remote_address + result;

read_bytes = preadv(fd, local, 1, offset);
Copy link
Member

Choose a reason for hiding this comment

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

You need to check for preadv and gate it by a macro as this is not available in all platforms IIRC

Copy link
Author

Choose a reason for hiding this comment

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

I gave this a go, but I think it's making the code a lot more complicated.

I now took a look at the histories of glibc and musl.
In musl, both both preadv and process_vm_readv were added in 2012 (searches: preadv, process_vm_readv)

In glibc preadv was added in glibc 2.10 and process_vm_readv in glibc 2.15 (man pages: preadv, process_vm_readv). Those were released in 2009 and 2012 respectively. So process_vm_readv is good enough as a guard here.

Seems Android is the one you are thinking of, https://android.googlesource.com/platform/bionic/+/refs/heads/main/libc/include/sys/uio.h
It states preadv is available at API level 24 and process_vm_readv at API level 23, which are from Android 7 (2016) and Android 6 (2015) respectively. I wasn't able to find somewhere stating which versions we support.

I think I will switch to pread and pwrite which have been available a lot longer. I tried to do that but I was forever unhappy with the name for the loop-inner count/len variable. I tried to_read, count, len_remaining, bytes_remaining, ... I think I will come back to this tomorrow.

Copy link
Member

Choose a reason for hiding this comment

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

preadv is available at API level 24 and process_vm_readv at API level 23, which are from Android 7 (2016) and Android 6 (2015) respectively. I wasn't able to find somewhere stating which versions we support.

This is defined in Android/android-env.sh. Python 3.13 requires API level 21 or greater, and Python 3.14 increases that to 24.

Copy link
Member

Choose a reason for hiding this comment

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

Given, this, I think is fine, just drop a comment so we know why are we not gating it :)

result += written;
} while ((size_t)written != local[0].iov_len);
return 0;
fallback:
Copy link
Member

Choose a reason for hiding this comment

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

Same feedback as the read path

@bedevere-app
Copy link

bedevere-app bot commented May 29, 2025

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@cakemanny cakemanny force-pushed the fallback-to-proc-mem branch from 90b08e6 to cbea7a2 Compare May 29, 2025 21:29
@bedevere-app
Copy link

bedevere-app bot commented May 29, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@cakemanny cakemanny force-pushed the fallback-to-proc-mem branch from cbea7a2 to 5fd8ff6 Compare May 29, 2025 21:44
@bedevere-app
Copy link

bedevere-app bot commented May 29, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@cakemanny cakemanny force-pushed the fallback-to-proc-mem branch from 5fd8ff6 to ef8ae45 Compare May 29, 2025 22:05
@bedevere-app
Copy link

bedevere-app bot commented May 29, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@cakemanny cakemanny force-pushed the fallback-to-proc-mem branch from ef8ae45 to f1eb6c0 Compare May 29, 2025 22:37
@bedevere-app
Copy link

bedevere-app bot commented May 29, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@pablogsal
Copy link
Member

@cakemanny one small comment: we squash merge so there is no need to rebase. It's easier to review if you just add commits on top so we don't need to review the full thing every iteration :)

@cakemanny
Copy link
Author

I have made the requested changes; please review again

@bedevere-app
Copy link

bedevere-app bot commented May 31, 2025

Thanks for making the requested changes!

@pablogsal: please review the changes made to this pull request.

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.

3 participants