Skip to content

aio: Read all message_length bytes from message response - #189

Merged
acrisci merged 2 commits into
altdesktop:masterfrom
sn4kebite:aio-message-recv
Oct 8, 2021
Merged

acrisci merged 2 commits into
altdesktop:masterfrom
sn4kebite:aio-message-recv

Conversation

@sn4kebite

Copy link
Copy Markdown
Contributor

sock_recv reads up to the specified amount of bytes, and can in some
situations return less than the requested amount. Make sure we read all
message_length bytes of the response before returning.

From my testing this fixes #175 which I can somewhat consistently reproduce by spamming get_tree calls.

`sock_recv` reads up to the specified amount of bytes, and can in some
situations return less than the requested amount. Make sure we read all
`message_length` bytes of the response before returning.
Comment thread i3ipc/aio/connection.py Outdated
logger.error('premature ending while reading message (%s bytes remaining)',
remaining_length)
break
message += buf

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this the most memory efficient way to make the message?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If you're referring to the temporary buffer, then we can probably limit the maximum size to read per iteration to avoid potentially storing two full copies of the message. When I was testing the message I was receiving was around 50k so I didn't see that as a problem.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I believe message.append(buf) might avoid a copy, or maybe using memoryview() might help. Let's just make sure we don't copy the memory every time. We know how much to allocate ahead of time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ah I see, we can swap it for a bytearray instead to avoid the copy on append. However that means we either need to construct a new bytes at the end (another copy), or allow _message() to return either bytearray or bytes. Since json.loads() accepts both bytes and bytearray the latter option should work fine.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok go ahead and do that and then it's good to go.

By making the message buffer a `bytearray` instead of `bytes` we can
append to the buffer without having to create a new instance for every
iteration. To avoid another copy we return this `bytearray` instead of
casting to `bytes`.

For consistency all return paths now return `bytearray` instead of
`bytes`.  This swap should not be an issue since all callers pass this
return value to `json.loads` which supports both `bytes` and
`bytearray`.
@acrisci

acrisci commented Oct 8, 2021

Copy link
Copy Markdown
Member

馃憤

@acrisci
acrisci merged commit 2e6533e into altdesktop:master Oct 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

get_tree() crashes with a JSON decode error

2 participants