Skip to content

GH-134453: Fix subprocess memoryview input handling on POSIX #134949

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 4 commits into
base: main
Choose a base branch
from

Conversation

gpshead
Copy link
Member

@gpshead gpshead commented May 30, 2025

Fix inconsistent subprocess.Popen.communicate() behavior between Windows and POSIX when using memoryview objects with non-byte elements as input.

On POSIX systems, the code was incorrectly comparing bytes written against element count instead of byte count, causing data truncation for large inputs with non-byte element types.

Changes:

  • Cast memoryview inputs to byte view when input is already a memoryview
  • Fix progress tracking to use len(input_view) instead of len(self._input)
  • Added tests for memoryview inputs

Fix inconsistent subprocess.Popen.communicate() behavior between Windows
and POSIX when using memoryview objects with non-byte elements as input.

On POSIX systems, the code was incorrectly comparing bytes written against
element count instead of byte count, causing data truncation for large
inputs with non-byte element types.

Changes:
- Cast memoryview inputs to byte view when input is already a memoryview
- Fix progress tracking to use len(input_view) instead of len(self._input)
- Add comprehensive test coverage for memoryview inputs

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>

pre-commit-whitespace-fixup
@gpshead gpshead force-pushed the subprocess-posix-input-memoryview branch from e1e8e52 to 6cd5c60 Compare May 30, 2025 18:42
@gpshead gpshead force-pushed the subprocess-posix-input-memoryview branch from 6cd5c60 to 7e1e75c Compare May 30, 2025 18:55
@gpshead gpshead requested a review from ZeroIntensity May 30, 2025 18:55
self.addCleanup(p.stdin.close)
(stdout, stderr) = p.communicate(mv)
self.assertEqual(stdout, test_data)
self.assertEqual(stderr, None)
Copy link
Member

Choose a reason for hiding this comment

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

Use assertIsNone

Suggested change
self.assertEqual(stderr, None)
self.assertIsNone(stderr, None)

self.addCleanup(p.stdin.close)
(stdout, stderr) = p.communicate(mv)
self.assertEqual(stdout, expected_bytes)
self.assertEqual(stderr, None)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
self.assertEqual(stderr, None)
self.assertIsNone(stderr, None)

Comment on lines +984 to +985
num_elements = (pipe_buf // 4) + 100
test_array = array.array('i', range(num_elements)) # 'i' = signed int (4 bytes each)
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, this test passes on the main branch. I think we want something like this:

Suggested change
num_elements = (pipe_buf // 4) + 100
test_array = array.array('i', range(num_elements)) # 'i' = signed int (4 bytes each)
num_elements = pipe_buf + 1
test_array = array.array('i', [1 for _ in range(num_elements)])

From what I can tell, the pipe is taking each integer as a single byte.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants