lwIP sockets: socket:close/1 does not release the processes selecting on the socket

Open Beginner friendly
#2,474 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 3 days

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
76/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
c, erlang

Research direction

Read src/libAtomVM/otp_socket.c, focusing on nif_socket_close and its OTP_SOCKET_LWIP branch; compare the suggested cleanup with socket_stop's BSD path. Check how socket_select_disown and ref_ticks are handled for both read and write selections. Done means closing an lwIP socket releases selecting processes and allows the resource destructor to run while those processes remain alive.

Written by the indexing model from the issue text.

Description

Affected: release-0.7 at ca1583068, lwIP socket backend (RP2 port; ESP32 uses BSD sockets).
Not fixed by #2345 (c4a2824f4), which extends the problem to the write direction.

What happens

On BSD sockets, socket:close/1 stops the select event and the stop callback
demonitors the selecting process, so the resource can be freed.

On lwIP, nif_socket_close only sends the closed notification. The selecting
process stays registered as owner: its pid, its monitor and the reference the
monitor holds on the resource are never released.

The socket resource (struct, rwlock, unread pbufs in received_list) is therefore
kept alive until the owning process exits, or selects again on that same socket.

A long-lived process that opens, uses and closes many sockets leaks one resource
per connection for its whole lifetime. With #2345, a process that waited for write
readiness in socket:send/2 leaks the same way.

How to reproduce (Pico W)

In one process, loop:

{ok, S} = socket:open(inet, stream, tcp),
ok = socket:connect(S, Peer),
{ok, _} = socket:recv(S, 0, 1000),   % arms a read select: this process becomes owner
ok = socket:close(S)

Add a trace to socket_dtor: it does not run while the process lives.
Free heap shrinks on every iteration.

Where

src/libAtomVM/otp_socket.c, nif_socket_close, #elif OTP_SOCKET_LWIP branch.

Suggested fix

After sending the closed notifications, disown both directions
(socket_select_disown on read_select and write_select, reset their
ref_ticks), as socket_stop does on BSD sockets.

Dominant language
Erlang
Stars
2.3k
Forks
171
Avg merge
4d 11h
Merged PRs (30d)
20

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from atomvm/AtomVM

All issues in atomvm/AtomVM

Similar issues

More Embedded & IoT issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.