From: Christian Heimes Date: Tue, 22 Mar 2022 16:08:51 +0000 (+0200) Subject: bpo-46315: Use fopencookie() to avoid dup() in _PyTokenizer_FindEncodingFilename... X-Git-Tag: v3.11.0a7~160 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9b889b5bda32c2610f98114d94750ba5f3260b58;p=thirdparty%2FPython%2Fcpython.git bpo-46315: Use fopencookie() to avoid dup() in _PyTokenizer_FindEncodingFilename (GH-32033) WASI does not have dup() and Emscripten's emulation is slow. --- diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 90dc8a2e3697..0941bcaaecc6 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -2072,6 +2072,39 @@ _PyTokenizer_Get(struct tok_state *tok, return result; } +#if defined(__wasi__) || defined(__EMSCRIPTEN__) +// fdopen() with borrowed fd. WASI does not provide dup() and Emscripten's +// dup() emulation with open() is slow. +typedef union { + void *cookie; + int fd; +} borrowed; + +static ssize_t +borrow_read(void *cookie, char *buf, size_t size) +{ + borrowed b = {.cookie = cookie}; + return read(b.fd, (void *)buf, size); +} + +static FILE * +fdopen_borrow(int fd) { + // supports only reading. seek fails. close and write are no-ops. + cookie_io_functions_t io_cb = {borrow_read, NULL, NULL, NULL}; + borrowed b = {.fd = fd}; + return fopencookie(b.cookie, "r", io_cb); +} +#else +static FILE * +fdopen_borrow(int fd) { + fd = _Py_dup(fd); + if (fd < 0) { + return NULL; + } + return fdopen(fd, "r"); +} +#endif + /* Get the encoding of a Python file. Check for the coding cookie and check if the file starts with a BOM. @@ -2091,12 +2124,7 @@ _PyTokenizer_FindEncodingFilename(int fd, PyObject *filename) const char *p_end = NULL; char *encoding = NULL; - fd = _Py_dup(fd); - if (fd < 0) { - return NULL; - } - - fp = fdopen(fd, "r"); + fp = fdopen_borrow(fd); if (fp == NULL) { return NULL; }