Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

extmod/modlwip.c: Fix crash when calling recv on listening socket#17333

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
andrewleech wants to merge1 commit intomicropython:master
base:master
Choose a base branch
Loading
fromandrewleech:socket_listed_recv

Conversation

andrewleech
Copy link
Contributor

Summary

Fix an issue where callingrecv() on a listening socket afteraccept() would cause a hard fault crash on
MicroPython hardware. This happens when user code incorrectly tries to receive data on the listening socket
instead of the accepted connection.

With this fix, MicroPython now properly raises anOSError witherrno=107 (ENOTCONN) similar to CPython,
instead of crashing. This makes the behavior consistent with standard socket implementations and improves error
handling.

The bug is demonstrated by the following code pattern:

importsockets=socket.socket(socket.AF_INET)s.bind(('0.0.0.0',8882))s.listen()s.accept()# connection not saveds.recv(3)# incorrectly calling recv on listening socket

Once data is sent to this socket from

importsockets=socket.socket(socket.AF_INET)s.connect(('127.0.0.1',8882))s.send(b'abc')

The first device crashes with a hard fault.

Testing

Added a new test file tests/multi_net/tcp_accept_recv_listen.py that demonstrates the fix by intentionally
triggering the error condition and checking for the appropriate exception.

Testing was performed against a pyboard-d (WIFI):
./run-multitests.py -i pyb:/dev/ttyACM0 -i cpython multi_net/tcp_accept_recv_listen.py

The test confirms that a proper OSError is raised with the correct errno value (107/ENOTCONN) instead of
crashing.


While this bug was found / fixed manually the unit test and documentation was created with AI support from Claude Code.

@github-actionsGitHub Actions
Copy link

Code size report:

   bare-arm:    +0 +0.000% minimal x86:    +0 +0.000%    unix x64:    +0 +0.000% standard      stm32:    +0 +0.000% PYBV10     mimxrt:    +0 +0.000% TEENSY40        rp2:    +8 +0.001% RPI_PICO_W       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS  qemu rv32:    +0 +0.000% VIRT_RV32

@andrewleechandrewleechforce-pushed thesocket_listed_recv branch 2 times, most recently from583b17e to210f5c9CompareMay 21, 2025 02:22
@@ -0,0 +1,39 @@
# Test recv on listening socket after accept without saving connection
Copy link
Member

Choose a reason for hiding this comment

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

Unless I'm missing something subtle, this test looks identical to the existingtcp_accept_recv.py test?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Oh yeah, I referenced that unit test when adding the one here but for some reason thought it was performing recv on the correct accepted socket rather than directly on the original socket.

I just ran the test between cpython and a rpi pico_2W and it doesn't hard fault reset, but nor does it raise an exception, it never receives anything and hangs.

But then I test again with pyb-d on current master and it passesmulti_net/tcp_accept_recv.py but reliably crashes onmulti_net/tcp_accept_recv_listen.py

Turns out yeah it's rather subtle

     s.bind(socket.getaddrinfo("0.0.0.0", PORT)[0][-1])-    s.listen()+    s.listen(1)     multitest.next()

With1 it all passes. Without (or with2 etc...) it crashes - aka if the original socket is still listening for new incomming connections it crashes.

Copy link
ContributorAuthor

@andrewleechandrewleechMay 21, 2025
edited
Loading

Choose a reason for hiding this comment

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

I've now consolidating the two tests, modding the original to expose the bug and re-tested before and after with pyb-d

Copy link
Member

Choose a reason for hiding this comment

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

Do you mean you combined the two tests into the original? Did you forget to push the changes?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry yes, turns out git had complained about me missing the-f on the push

@dpgeorgedpgeorge added the extmodRelates to extmod/ directory in source labelMay 21, 2025
@codecovCodecov
Copy link

codecovbot commentedMay 21, 2025
edited
Loading

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.54%. Comparing base(186caf9) to head(baaf54f).
Report is 13 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@##           master   #17333   +/-   ##=======================================  Coverage   98.54%   98.54%           =======================================  Files         169      169             Lines       21898    21898           =======================================  Hits        21579    21579             Misses        319      319

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report?Share it here.

🚀 New features to boost your workflow:
  • ❄️Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@@ -11,13 +11,14 @@ def instance0():
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(socket.getaddrinfo("0.0.0.0", PORT)[0][-1])
s.listen(1)
s.listen()
Copy link
Member

Choose a reason for hiding this comment

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

This might change the original test with 1 as an argument.

Maybe it's better to do a loop here to perform both tests (with no argument, and with an argument of 1, and then maybe some other values like 0 for good measure).

Also need the client to do a loop as well, and usemultitest.wait() andmultitest.broadcast() to sync with the server.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Ok, I've got an updated looping test just pushed that passes on the pyb-d with this patch applied.

Add check to prevent calling recv on a socket in the listening state.This prevents a crash/hard fault when user code mistakenly tries torecv on the listening socket instead of on the accepted connection.Add corresponding test case to demonstrate the bug.Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
@projectgusprojectgus self-requested a reviewMay 21, 2025 23:43
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@dpgeorgedpgeorgedpgeorge left review comments

@projectgusprojectgusAwaiting requested review from projectgus

Assignees
No one assigned
Labels
extmodRelates to extmod/ directory in source
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

3 participants
@andrewleech@dpgeorge@pi-anl

[8]ページ先頭

©2009-2025 Movatter.jp