pkt-line: eliminate the need for static buffer in packet_write_gently()

Teach `packet_write_gently()` to write the pkt-line header and the actual buffer in 2 separate calls to `write_in_full()` and avoid the need for a static buffer, thread-safe scratch space, or an excessively large stack buffer. Change `write_packetized_from_fd()` to allocate a temporary buffer rather than using a static buffer to avoid similar issues here. These changes are intended to make it easier to use pkt-line routines in a multi-threaded context with multiple concurrent writers writing to different streams. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff Hostetler committed Mar 15, 2021 at 21:08 UTC 7455e05e4e750451eb3c33359a2bc9050156750c
1 file changed +20 -8
pkt-line.c
+20 -8
@@ -196,17 +196,26 @@ int packet_write_fmt_gently(int fd, const char *fmt, ...)
196
197 static int packet_write_gently(const int fd_out, const char *buf, size_t size)
198 {
199 - static char packet_write_buffer[LARGE_PACKET_MAX];
199 + char header[4];
200 size_t packet_size;
201
202 - if (size > sizeof(packet_write_buffer) - 4)
202 + if (size > LARGE_PACKET_DATA_MAX)
203 return error(_("packet write failed - data exceeds max packet size"));
204
205 packet_trace(buf, size, 1);
206 packet_size = size + 4;
207 - set_packet_header(packet_write_buffer, packet_size);
208 - memcpy(packet_write_buffer + 4, buf, size);
209 - if (write_in_full(fd_out, packet_write_buffer, packet_size) < 0)
207 +
208 + set_packet_header(header, packet_size);
209 +
210 + /*
211 + * Write the header and the buffer in 2 parts so that we do
212 + * not need to allocate a buffer or rely on a static buffer.
213 + * This also avoids putting a large buffer on the stack which
214 + * might have multi-threading issues.
215 + */
216 +
217 + if (write_in_full(fd_out, header, 4) < 0 ||
218 + write_in_full(fd_out, buf, size) < 0)
219 return error(_("packet write failed"));
220 return 0;
221 }
@@ -244,20 +253,23 @@ void packet_buf_write_len(struct strbuf *buf, const char *data, size_t len)
253
254 int write_packetized_from_fd(int fd_in, int fd_out)
255 {
247 - static char buf[LARGE_PACKET_DATA_MAX];
256 + char *buf = xmalloc(LARGE_PACKET_DATA_MAX);
257 int err = 0;
258 ssize_t bytes_to_write;
259
260 while (!err) {
252 - bytes_to_write = xread(fd_in, buf, sizeof(buf));
253 - if (bytes_to_write < 0)
261 + bytes_to_write = xread(fd_in, buf, LARGE_PACKET_DATA_MAX);
262 + if (bytes_to_write < 0) {
263 + free(buf);
264 return COPY_READ_ERROR;
265 + }
266 if (bytes_to_write == 0)
267 break;
268 err = packet_write_gently(fd_out, buf, bytes_to_write);
269 }
270 if (!err)
271 err = packet_flush_gently(fd_out);
272 + free(buf);
273 return err;
274 }
275