This issue tracker has been migrated to GitHub ,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2014年04月09日 18:24 by Dima.Tisnek, last changed 2022年04月11日 14:58 by admin. This issue is now closed.
| Messages (17) | |||
|---|---|---|---|
| msg215832 - (view) | Author: Dima Tisnek (Dima.Tisnek) * | Date: 2014年04月09日 18:24 | |
os.fdopen() should either:
* consume file descriptor and return file/io object, or
* leave file descriptor alone and raise an exception
this invariant is broken in the following test case:
fd = os.open("/", os.O_RDONLY)
try:
obj = os.fdopen(fd, "r")
except EnvironmentError:
os.close(fd) # cleanup
what happens:
fd = os.open("/", os.O_RDONLY) --> some fd
os.fdopen(fd, "r") --> exception, fd refers to a directory
os.close(fd) --> exception, no such fd
For reference:
1. invariant is held in Python 3.3.
2. following positive test case works correctly
fd = os.open("/etc/passwd", os.O_RDONLY)
try: obj = os.fdopen(fd, "r") # success
except EnvironmentError: os.close(fd) # not reached
3. following negative test case works correctly
fd = os.open("/etc/passwd", os.O_RDONLY)
try: obj = os.fdopen(fd, "w") # wrong mode on purpose
except EnvironmentError: os.close(fd) # closed ok
|
|||
| msg215835 - (view) | Author: Benjamin Peterson (benjamin.peterson) * (Python committer) | Date: 2014年04月09日 19:01 | |
I think this is just won't fix. I agree the behavior in 3.x is better, but at least fdopen() is consistent about closing in 2.x, so you could work around it by dupping the fd. |
|||
| msg215837 - (view) | Author: Dima Tisnek (Dima.Tisnek) * | Date: 2014年04月09日 19:22 | |
Benjamin, I think you missed the key point: file + matching mode -> fd eaten, object created file + mode mismatch -> fd remains, exception raised dir + matching mode -> fd eaten, exception raised The issue is about resouce (fd) management Thus, how can user code handle the error without either leaking file descriptor or possibly closing someone else's file descriptor? |
|||
| msg215838 - (view) | Author: Benjamin Peterson (benjamin.peterson) * (Python committer) | Date: 2014年04月09日 19:26 | |
Ah, you're right. I misread the code. |
|||
| msg215839 - (view) | Author: Roundup Robot (python-dev) (Python triager) | Date: 2014年04月09日 19:40 | |
New changeset 4a3b455abf76 by Benjamin Peterson in branch '2.7': make sure fdopen always closes the fd in error cases (closes #21191) http://hg.python.org/cpython/rev/4a3b455abf76 |
|||
| msg215840 - (view) | Author: Dima Tisnek (Dima.Tisnek) * | Date: 2014年04月09日 19:48 | |
I don't like proposed patch -- it changes semantics of more (?) common failure modes. I think it's best to keep semantics in line with Python 3.3 -- if fdopen fails, it leaves file descriptor alone. |
|||
| msg215841 - (view) | Author: Benjamin Peterson (benjamin.peterson) * (Python committer) | Date: 2014年04月09日 19:52 | |
On Wed, Apr 9, 2014, at 12:48, Dima Tisnek wrote: > > Dima Tisnek added the comment: > > I don't like proposed patch -- it changes semantics of more (?) common > failure modes. I don't know if opening the file with the wrong mode is any more wrong than opening a directory. |
|||
| msg215844 - (view) | Author: Dima Tisnek (Dima.Tisnek) * | Date: 2014年04月09日 20:18 | |
Good point. Personally I think it's more pythonic to consume fd only on success. I accept that's just an opinion. In any case, let's keep error semantics in py2.7 and py3.3 same. |
|||
| msg215851 - (view) | Author: Benjamin Peterson (benjamin.peterson) * (Python committer) | Date: 2014年04月09日 21:50 | |
On Wed, Apr 9, 2014, at 13:18, Dima Tisnek wrote: > > Dima Tisnek added the comment: > > Good point. > > Personally I think it's more pythonic to consume fd only on success. I > accept that's just an opinion. > > In any case, let's keep error semantics in py2.7 and py3.3 same. Unfortunately, it's not easy to implement with the 2.7 implementation of the file type. |
|||
| msg215859 - (view) | Author: Benjamin Peterson (benjamin.peterson) * (Python committer) | Date: 2014年04月10日 00:19 | |
I should note the C level fdopen has the the 2.x semantics. |
|||
| msg215895 - (view) | Author: Dima Tisnek (Dima.Tisnek) * | Date: 2014年04月10日 17:46 | |
I'm not sure if you are referring to Python's C-level fdopen or GNU libc fdopen.
GNU libc fdopen does not consume file descriptor on error:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
int main(int argc, char** argv)
{
int fd = -1;
int rv = 0;
FILE* fh = NULL;
if (argc<3) return 1;
errno = 0;
fd = open(argv[1], O_RDONLY);
printf("got fd %d errno %d text %s\n", fd, errno, strerror(errno));
errno = 0;
fh = fdopen(fd, argv[2]);
printf("got fh %x errno %d text %s\n", fh, errno, strerror(errno));
errno = 0;
rv = close(fd);
printf("got rv %d errno %d text %s\n", rv, errno, strerror(errno));
}
[dima@bmg ~]$ ./a.out /etc/passwd w
got fd 4 errno 0 text Success
got fh 0 errno 22 text Invalid argument
got rv 0 errno 0 text Success
To be fair, GNU libc fdopen doesn't consider it an error to use a file descriptor that refers to a directory, which is the crux of this bug.
Anyhow, point is the semantics change your patch brings in sets Python 2.7+ in contrast with both Python 3.x and GNU libc.
Perhaps if it's too hard to implement properly, it's better to leave this issue as won't fix / technical limitation?
|
|||
| msg215912 - (view) | Author: Benjamin Peterson (benjamin.peterson) * (Python committer) | Date: 2014年04月10日 22:55 | |
On Thu, Apr 10, 2014, at 10:46, Dima Tisnek wrote:
>
> Dima Tisnek added the comment:
>
> I'm not sure if you are referring to Python's C-level fdopen or GNU libc
> fdopen.
>
> GNU libc fdopen does not consume file descriptor on error:
>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <string.h>
> #include <errno.h>
> #include <unistd.h>
>
>
> int main(int argc, char** argv)
> {
> int fd = -1;
> int rv = 0;
> FILE* fh = NULL;
> if (argc<3) return 1;
>
> errno = 0;
> fd = open(argv[1], O_RDONLY);
> printf("got fd %d errno %d text %s\n", fd, errno, strerror(errno));
>
> errno = 0;
> fh = fdopen(fd, argv[2]);
> printf("got fh %x errno %d text %s\n", fh, errno, strerror(errno));
>
> errno = 0;
> rv = close(fd);
> printf("got rv %d errno %d text %s\n", rv, errno, strerror(errno));
> }
>
> [dima@bmg ~]$ ./a.out /etc/passwd w
> got fd 4 errno 0 text Success
> got fh 0 errno 22 text Invalid argument
> got rv 0 errno 0 text Success
>
> To be fair, GNU libc fdopen doesn't consider it an error to use a file
> descriptor that refers to a directory, which is the crux of this bug.
I meant once you manage to get fdopen to succeed, the fd has basically
been consumed.
>
> Anyhow, point is the semantics change your patch brings in sets Python
> 2.7+ in contrast with both Python 3.x and GNU libc.
I realize.
>
> Perhaps if it's too hard to implement properly, it's better to leave this
> issue as won't fix / technical limitation?
I mean if you'd prefer for it to just be inconsistent in 2.x...
|
|||
| msg215921 - (view) | Author: Dima Tisnek (Dima.Tisnek) * | Date: 2014年04月11日 09:40 | |
I think consistency between Python versions is just as important as consistency between fd types. Here's my hack quickfix outline: fd = os.open(...) try: if not stat.S_ISREG(os.fstat(fd).st_mode): raise OSError(None, "Not a regular file", ...) f = os.fdopen(fd, ...) except EnvironmentError: os.close(fd) Can something like this be implemented in os.py There's already a check `if not isinstance(fd, int): raise ...` Granted we'd have to get fd type check exactly right. fdopen should probably succeed for regular files, pipes, char devices, block device, ptry's ... fdopen should fail where underlying implementation fails, i.e. directories, sockets(?), epoll(?), timerfd(?) There's a list at http://en.wikipedia.org/wiki/File_descriptor I'm not sure about some types. P.S. I wish there was a way to rescue fd from FILE*, but nothing like that seems to exist... P.P.S. another option is to always use dup(), but that may break existing programs is they expect fd == fdopen(fd).fileno() |
|||
| msg216066 - (view) | Author: Benjamin Peterson (benjamin.peterson) * (Python committer) | Date: 2014年04月14日 04:05 | |
Feel free to submit a patch. On Fri, Apr 11, 2014, at 2:40, Dima Tisnek wrote: > > Dima Tisnek added the comment: > > I think consistency between Python versions is just as important as > consistency between fd types. > > Here's my hack quickfix outline: > > fd = os.open(...) > try: > if not stat.S_ISREG(os.fstat(fd).st_mode): > raise OSError(None, "Not a regular file", ...) > f = os.fdopen(fd, ...) > except EnvironmentError: > os.close(fd) > > Can something like this be implemented in os.py > There's already a check `if not isinstance(fd, int): raise ...` > > Granted we'd have to get fd type check exactly right. Well, you just have check exactly what it's checking now, which seems to be !S_ISDIR. > fdopen should probably succeed for regular files, pipes, char devices, > block device, ptry's ... > fdopen should fail where underlying implementation fails, i.e. > directories, sockets(?), epoll(?), timerfd(?) > > There's a list at http://en.wikipedia.org/wiki/File_descriptor > I'm not sure about some types. > > P.S. I wish there was a way to rescue fd from FILE*, but nothing like > that seems to exist... Yes, this is one of the main problems. > > P.P.S. another option is to always use dup(), but that may break existing > programs is they expect fd == fdopen(fd).fileno() |
|||
| msg216252 - (view) | Author: Roundup Robot (python-dev) (Python triager) | Date: 2014年04月14日 23:46 | |
New changeset 339c79791b65 by Benjamin Peterson in branch '2.7': when an exception is raised in fdopen, never close the fd (changing on my mind on #21191) http://hg.python.org/cpython/rev/339c79791b65 |
|||
| msg216283 - (view) | Author: Dima Tisnek (Dima.Tisnek) * | Date: 2014年04月15日 09:34 | |
Banjamin, Your patch looks good to me! I have a small concern regarding "We now know we will succeed..." -- should there be a test case to make sure fstat test here matches whatever test is/was done on a lower level? Or is your code now such that it will explicitly succeed because it doesn't call anything that can fail after the comment? |
|||
| msg216285 - (view) | Author: Benjamin Peterson (benjamin.peterson) * (Python committer) | Date: 2014年04月15日 12:58 | |
On Tue, Apr 15, 2014, at 2:34, Dima Tisnek wrote: > > Dima Tisnek added the comment: > > Banjamin, Your patch looks good to me! > > I have a small concern regarding "We now know we will succeed..." -- > should there be a test case to make sure fstat test here matches whatever > test is/was done on a lower level? > > Or is your code now such that it will explicitly succeed because it > doesn't call anything that can fail after the comment? That's what I mean. |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022年04月11日 14:58:01 | admin | set | github: 65390 |
| 2014年04月15日 12:58:39 | benjamin.peterson | set | messages: + msg216285 |
| 2014年04月15日 09:34:17 | Dima.Tisnek | set | messages: + msg216283 |
| 2014年04月14日 23:46:08 | python-dev | set | messages: + msg216252 |
| 2014年04月14日 04:05:29 | benjamin.peterson | set | messages: + msg216066 |
| 2014年04月11日 09:40:20 | Dima.Tisnek | set | messages: + msg215921 |
| 2014年04月10日 22:55:33 | benjamin.peterson | set | messages: + msg215912 |
| 2014年04月10日 17:46:50 | Dima.Tisnek | set | messages: + msg215895 |
| 2014年04月10日 00:19:35 | benjamin.peterson | set | messages: + msg215859 |
| 2014年04月09日 21:50:02 | benjamin.peterson | set | messages: + msg215851 |
| 2014年04月09日 20:18:38 | Dima.Tisnek | set | messages: + msg215844 |
| 2014年04月09日 19:52:59 | benjamin.peterson | set | messages: + msg215841 |
| 2014年04月09日 19:48:55 | Dima.Tisnek | set | messages: + msg215840 |
| 2014年04月09日 19:40:36 | python-dev | set | status: open -> closed nosy: + python-dev messages: + msg215839 resolution: fixed stage: resolved |
| 2014年04月09日 19:26:03 | benjamin.peterson | set | status: closed -> open resolution: wont fix -> (no value) messages: + msg215838 |
| 2014年04月09日 19:22:54 | Dima.Tisnek | set | messages: + msg215837 |
| 2014年04月09日 19:01:06 | benjamin.peterson | set | status: open -> closed nosy: + benjamin.peterson messages: + msg215835 resolution: wont fix |
| 2014年04月09日 18:24:55 | Dima.Tisnek | create | |