Skip to content

[2.7] bpo-36337: Use ssize_t and size_t for socket.send()/sendall()#12397

Merged
vstinner merged 11 commits intopython:2.7from
matrixise:bpo-36337
Mar 19, 2019
Merged

[2.7] bpo-36337: Use ssize_t and size_t for socket.send()/sendall()#12397
vstinner merged 11 commits intopython:2.7from
matrixise:bpo-36337

Conversation

@matrixise
Copy link
Copy Markdown
Member

@matrixise matrixise commented Mar 18, 2019

This PR is not yet completed (missing tests), I have "backported" a patch from 3.x.

https://bugs.python.org/issue36337

@matrixise matrixise changed the title bpo-36337: Use ssize_t and size_t for socket.send()/sendall() [2.7] bpo-36337: Use ssize_t and size_t for socket.send()/sendall() Mar 18, 2019
@vstinner
Copy link
Copy Markdown
Member

I don't think that a test is needed: I cannot find a test on master.

Your PR is wrong on Windows. Look at the master branch:

#ifdef MS_WINDOWS
    if (ctx->len > INT_MAX)
        ctx->len = INT_MAX;
    ctx->result = send(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags);
#else
    ctx->result = send(s->sock_fd, ctx->buf, ctx->len, ctx->flags);
#endif

On Windows, the type of send() length argument is int, not size_t.

Comment thread Modules/socketmodule.c Outdated
@matrixise matrixise marked this pull request as ready for review March 18, 2019 12:18
Comment thread Modules/socketmodule.c
char *buf;
int len, n = -1, flags = 0, timeout;
int flags = 0, timeout;
Py_ssize_t len, n = -1;
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.

return PyInt_FromLong((long)n); below is wrong

@bedevere-bot
Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@matrixise
Copy link
Copy Markdown
Member Author

I have made the requested changes; please review again

@bedevere-bot
Copy link
Copy Markdown

Thanks for making the requested changes!

@vstinner: please review the changes made to this pull request.

Comment thread Modules/socketmodule.c
if (!timeout)
if (!timeout) {
#ifdef __VMS
n = sendsegmented(s->sock_fd, buf, len, flags);
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.

That's wrong: sendsegmented() len type is int, not Py_ssize_t. Don't forget the VMS! :-)

@@ -0,0 +1,3 @@
Use ssize_t and size_t instead of int for the send() function (see
http://man7.org/linux/man-pages/man2/send.2.html (Linux) and
https://nixdoc.net/man-pages/FreeBSD/man2/send.2.html (FreeBSD)).
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 propose:

Fix buffer overflow in :meth:~socket.socket.send and :meth:~socket.socket.sendall methods of :func:socket.socket for data larger than 2 GiB.

@bedevere-bot
Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@matrixise
Copy link
Copy Markdown
Member Author

I have made the requested changes; please review again

@bedevere-bot
Copy link
Copy Markdown

Thanks for making the requested changes!

@vstinner: please review the changes made to this pull request.

Comment thread Modules/socketmodule.c Outdated
if (!timeout) {
#ifdef __VMS
n = sendsegmented(s->sock_fd, buf, len, flags);
n = sendsegmented(s->sock_fd, buf, (int)len, flags);
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.

(int)len is unsafe if len is larger than INT_MAX. You should modify sendsegmented() to accept Py_ssize_t rather than int.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

👍 good catch and I was thinking about this problem.

Copy link
Copy Markdown
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

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

LGTM.

The subtle side effect of this change is that send() and sendall() now always return a Python 'long' object, whereas they always returned a Python 'int' object previously. I think that it's acceptable, but it might be risky to push so change late in 2.7 lifetime (EOL scheduled at the beginning of next year).

On the other side, currently, calling sendall() with more than 2 GiB data loose data. But well, who does that with Python 2.7?

I would prefer to have the review of another core dev.

@benjaminp @serhiy-storchaka @pablogsal: Would you mind to review this change? Do you think that it's ok to change send/sendall return type (int => long, supposed to be compatible)?

Comment thread Modules/socketmodule.c Outdated
@matrixise
Copy link
Copy Markdown
Member Author

I have made the requested changes; please review again

@serhiy-storchaka @vstinner

@bedevere-bot
Copy link
Copy Markdown

Thanks for making the requested changes!

@vstinner: please review the changes made to this pull request.

Comment thread Modules/socketmodule.c
unsigned int segment;

segment = (remaining >= SEGMENT_SIZE ? SEGMENT_SIZE : remaining);
segment = ((size_t)remaining >= SEGMENT_SIZE ? SEGMENT_SIZE : (unsigned int) remaining);
Copy link
Copy Markdown
Member

@pablogsal pablogsal Mar 18, 2019

Choose a reason for hiding this comment

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

Wait, is this cast safe? In C99 ssize_t can be an unsigned long, unless I am missing something. I think you need:

Py_SAFE_DOWNCAST(remaining, Py_ssize_t, unsigned int)

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.

SEGMENT_SIZE is 32 KiB: remaining is only casted for values between [0; 32 KiB]:

#define SEGMENT_SIZE (32 * 1024 -1)

Copy link
Copy Markdown
Member

@pablogsal pablogsal left a comment

Choose a reason for hiding this comment

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

LGTM

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.

7 participants