Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o, Brian Dolbec <dolsen@g.o>
Subject: Re: [gentoo-portage-dev] [PATCH] _writer: fix unsafe finally clause (bug 728580)
Date: Thu, 18 Jun 2020 18:09:20
Message-Id: cf54fa95-94c5-6ae6-5a3c-098ef3fd093c@gentoo.org
In Reply to: Re: [gentoo-portage-dev] [PATCH] _writer: fix unsafe finally clause (bug 728580) by Brian Dolbec
1 On 6/18/20 7:13 AM, Brian Dolbec wrote:
2 > On Thu, 18 Jun 2020 00:35:48 -0700
3 > Zac Medico <zmedico@g.o> wrote:
4 >
5 >> In the coroutine finally clause, do not call remove_writer in cases
6 >> where fd has been closed and then re-allocated to a concurrent
7 >> coroutine as in bug 716636.
8 >>
9 >> Also, assume that the caller will put the file in non-blocking mode
10 >> and close the file when done, so that this function is suitable for
11 >> use within a loop.
12 >>
13 >> Bug: https://bugs.gentoo.org/728580
14 >> Signed-off-by: Zac Medico <zmedico@g.o>
15 >> ---
16 >> lib/portage/util/futures/_asyncio/process.py | 11 ++++-
17 >> lib/portage/util/futures/_asyncio/streams.py | 50
18 >> ++++++++++---------- 2 files changed, 33 insertions(+), 28
19 >> deletions(-)
20 >>
21 >> diff --git a/lib/portage/util/futures/_asyncio/process.py
22 >> b/lib/portage/util/futures/_asyncio/process.py index
23 >> 020164c9b..2d3e9b0fd 100644 ---
24 >> a/lib/portage/util/futures/_asyncio/process.py +++
25 >> b/lib/portage/util/futures/_asyncio/process.py @@ -1,9 +1,12 @@
26 >> -# Copyright 2018 Gentoo Foundation
27 >> +# Copyright 2018-2020 Gentoo Authors
28 >> # Distributed under the terms of the GNU General Public License v2
29 >>
30 >> +import os
31 >> +
32 >> import portage
33 >> portage.proxy.lazyimport.lazyimport(globals(),
34 >> 'portage.util.futures:asyncio',
35 >> + 'portage.util.futures.unix_events:_set_nonblocking',
36 >> )
37 >> from portage.util.futures._asyncio.streams import _reader, _writer
38 >> from portage.util.futures.compat_coroutine import coroutine,
39 >> coroutine_return @@ -59,7 +62,11 @@ class _Process(object):
40 >> if input is not None:
41 >> if self._proc.stdin is None:
42 >> raise TypeError('communicate:
43 >> expected file or int, got {}'.format(type(self._proc.stdin)))
44 >> - writer =
45 >> asyncio.ensure_future(_writer(self._proc.stdin, input),
46 >> loop=self._loop)
47 >> + stdin = self._proc.stdin
48 >> + stdin = os.fdopen(stdin, 'wb', 0) if
49 >> isinstance(stdin, int) else stdin
50 >> + _set_nonblocking(stdin.fileno())
51 >> + writer =
52 >> asyncio.ensure_future(_writer(stdin, input, loop=self._loop),
53 >> loop=self._loop)
54 >> + writer.add_done_callback(lambda writer:
55 >> stdin.close())
56 >> try:
57 >> yield asyncio.wait(futures + [self.wait()],
58 >> loop=self._loop) diff --git
59 >> a/lib/portage/util/futures/_asyncio/streams.py
60 >> b/lib/portage/util/futures/_asyncio/streams.py index
61 >> 650a16491..870307e1e 100644 ---
62 >> a/lib/portage/util/futures/_asyncio/streams.py +++
63 >> b/lib/portage/util/futures/_asyncio/streams.py @@ -1,4 +1,4 @@ -#
64 >> Copyright 2018 Gentoo Foundation +# Copyright 2018-2020 Gentoo Authors
65 >> # Distributed under the terms of the GNU General Public License v2
66 >>
67 >> import errno
68 >> @@ -8,7 +8,6 @@ import portage
69 >> portage.proxy.lazyimport.lazyimport(globals(),
70 >> '_emerge.PipeReader:PipeReader',
71 >> 'portage.util.futures:asyncio',
72 >> - 'portage.util.futures.unix_events:_set_nonblocking',
73 >> )
74 >> from portage.util.futures.compat_coroutine import coroutine
75 >>
76 >> @@ -59,38 +58,37 @@ class _Reader(object):
77 >> @coroutine
78 >> def _writer(output_file, content, loop=None):
79 >> """
80 >> - Asynchronously write bytes to output file, and close it when
81 >> - done. If an EnvironmentError other than EAGAIN is
82 >> encountered,
83 >> - which typically indicates that the other end of the pipe has
84 >> - close, the error is raised. This function is a coroutine.
85 >> + Asynchronously write bytes to output file. The output file is
86 >> + assumed to be in non-blocking mode. If an EnvironmentError
87 >> + other than EAGAIN is encountered, which typically indicates
88 >> that
89 >> + the other end of the pipe has closed, the error is raised.
90 >> + This function is a coroutine.
91 >>
92 >> - @param output_file: output file descriptor
93 >> - @type output_file: file or int
94 >> + @param output_file: output file
95 >> + @type output_file: file object
96 >> @param content: content to write
97 >> @type content: bytes
98 >> @param loop: asyncio.AbstractEventLoop (or compatible)
99 >> @type loop: event loop
100 >> """
101 >> - fd = output_file if isinstance(output_file, int) else
102 >> output_file.fileno()
103 >> - _set_nonblocking(fd)
104 >> loop = asyncio._wrap_loop(loop)
105 >> - try:
106 >> - while content:
107 >> + fd = output_file.fileno()
108 >> + while content:
109 >> + try:
110 >> + content = content[os.write(fd, content):]
111 >> + except EnvironmentError as e:
112 >> + if e.errno != errno.EAGAIN:
113 >> + raise
114 >> waiter = loop.create_future()
115 >> - loop.add_writer(fd, lambda:
116 >> waiter.set_result(None))
117 >> + loop.add_writer(fd, lambda: waiter.done() or
118 >> waiter.set_result(None)) try:
119 >> yield waiter
120 >> - while content:
121 >> - try:
122 >> - content =
123 >> content[os.write(fd, content):]
124 >> - except EnvironmentError as e:
125 >> - if e.errno ==
126 >> errno.EAGAIN:
127 >> - break
128 >> - else:
129 >> - raise
130 >> finally:
131 >> - loop.remove_writer(fd)
132 >> - except GeneratorExit:
133 >> - raise
134 >> - finally:
135 >> - os.close(output_file) if isinstance(output_file,
136 >> int) else output_file.close()
137 >> + # The loop and output file may have
138 >> been closed.
139 >> + if not loop.is_closed():
140 >> + waiter.done() or
141 >> waiter.cancel()
142 >> + # Do not call remove_writer
143 >> in cases where fd has
144 >> + # been closed and then
145 >> re-allocated to a concurrent
146 >> + # coroutine as in bug 716636.
147 >> + if not output_file.closed:
148 >> +
149 >> loop.remove_writer(fd)
150 >
151 >
152 > looks fine to me
153 >
154
155 Thanks, merged:
156
157 https://gitweb.gentoo.org/proj/portage.git/commit/?id=92be5a02e452eb0810d2974bc7fa5ee2056ef8e7
158 --
159 Thanks,
160 Zac

Attachments

File name MIME type
signature.asc application/pgp-signature