]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46315: Use fopencookie() to avoid dup() in _PyTokenizer_FindEncodingFilename...
authorChristian Heimes <christian@python.org>
Tue, 22 Mar 2022 16:08:51 +0000 (18:08 +0200)
committerGitHub <noreply@github.com>
Tue, 22 Mar 2022 16:08:51 +0000 (17:08 +0100)
WASI does not have dup() and Emscripten's emulation is slow.

Parser/tokenizer.c

index 90dc8a2e369714472d89a29a825296bbaa4c9e91..0941bcaaecc62774c488fbefa41539cb8e0a1c4f 100644 (file)
@@ -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;
     }