[issue46715] asyncio.create_unix_server has an off-by-one error concerning the backlog parameter

2022-02-10 Thread John Snow


New submission from John Snow :

Hi, asyncio.create_unix_server appears to treat the "backlog" parameter as 
where 0 means that *no connection will ever possibly be pending*, which (at the 
very least for UNIX sockets on my machine) is untrue.

Consider a (non-asyncio) server:

```python
import os, socket, sys, time

sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind('test.sock')

sock.listen(backlog=0)

while True:
print('.', end='', file=sys.stderr)
time.sleep(1)
```

This server never calls accept(), and uses a backlog of zero. However, a client 
can actually still successfully call connect against such a server:

```python
import os, socket, time

sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(False)

sock.connect('test.sock')
print("Connected!")
```

When run against the server example, the first invocation of this client will 
actually connect successfully (Surprising, but that's how the C syscalls work 
too, so... alright) but the second invocation of this client will raise 
BlockingIOError (EAGAIN).

Further, if we amend the first server example to actually call accept(), it 
will succeed when the first client connects -- demonstrating that the actual 
total queue length here was actually effectively 1, not 0.

(i.e. there's always room for at least one connection to be considered, and the 
backlog counts everybody else.)

However, in asyncio.BaseSelectorEventLoop._accept_connection(...), the code 
uses `for _ in range(backlog)` to determine the maximum number of accept calls 
to make. When backlog is set to zero, this means we will *never* call accept, 
even when there are pending connections.

Note that when backlog=1, this actually allows for *two* pending connections 
before clients are rejected, but this loop will only fire once. This behavior 
is surprising, because backlog==0 means we'll accept no clients, but backlog==1 
means we will allow for two to enqueue before accepting both. There is 
seemingly no way with asyncio to actually specify "Exactly one pending 
connection".

I think this loop should be amended to reflect the actual truth of the backlog 
parameter, and it should iterate over `backlog + 1`. This does necessitate a 
change to `Lib/test/test_asyncio/test_selector_events.py` which believes that 
backlog=100 means that accept() should be called 100 times (instead of 101.)

A (very) simple fix is attached here; if it seems sound, I can spin a real PR 
on GitHub.

--
components: asyncio
files: issue.patch
keywords: patch
messages: 413025
nosy: asvetlov, jnsnow, yselivanov
priority: normal
severity: normal
status: open
title: asyncio.create_unix_server has an off-by-one error concerning the 
backlog parameter
type: behavior
versions: Python 3.10, Python 3.11, Python 3.7, Python 3.8, Python 3.9
Added file: https://bugs.python.org/file50618/issue.patch

___
Python tracker 
<https://bugs.python.org/issue46715>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue43232] Prohibit previously deprecated operations on asyncio.trsock.TransportSocket

2021-09-17 Thread John Snow


John Snow  added the comment:

Without sendmsg(), is there any other way to send SCM_RIGHTS ancillary messages 
over an asyncio-managed UNIX socket?

(Is there a better place to discuss this? Kindly point me in the right 
direction if so.)

--
nosy: +jnsnow

___
Python tracker 
<https://bugs.python.org/issue43232>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26474] Memory leak at malloc_closure.c

2016-03-02 Thread John Snow

New submission from John Snow:

malloc_closere.c holds a static list of items: free_list.
The items are being allocated in the more_core method using VirtualAlloc / 
mmap. However they never get released.

Here is the allocation code:

#ifdef MS_WIN32
item = (ITEM *)VirtualAlloc(NULL,
   count * sizeof(ITEM),
   MEM_COMMIT,
   PAGE_EXECUTE_READWRITE);
if (item == NULL)
return;
#else
item = (ITEM *)mmap(NULL,
count * sizeof(ITEM),
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0);
if (item == (void *)MAP_FAILED)
return;
#endif

--
components: ctypes
messages: 261138
nosy: John_Snow
priority: normal
severity: normal
status: open
title: Memory leak at malloc_closure.c
type: resource usage
versions: Python 2.7

___
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue26474>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com