Prechádzať zdrojové kódy

Improve readlinkat_dup() to handle symlink size correctly (#4229)

* In readlinkat_dup(), use fstatat() to estimate size first.
* Reduce additional space in samples/file
liang.he 8 mesiacov pred
rodič
commit
1a72dcf34f

+ 34 - 21
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c

@@ -1222,43 +1222,56 @@ __wasi_errno_t
 readlinkat_dup(os_file_handle handle, const char *path, size_t *p_len,
                char **out_buf)
 {
-    char *buf = NULL;
-    size_t len = 32;
-    size_t len_org = len;
+    __wasi_errno_t error;
+    struct __wasi_filestat_t stat = { 0 };
+    size_t buf_len;
+
+    /*
+     * use fstatat to get a better estimation
+     * If path is a symbolic link, do not dereference it:
+     * instead return information about the link itself,
+     * like lstat().
+     */
+    error = os_fstatat(handle, path, &stat, 0);
+    if (error != __WASI_ESUCCESS) {
+        stat.st_size = 0;
+    }
 
+    /*
+     * Some magic symlinks report `st_size` as zero. In that case, take
+     * 32 as the initial buffer size. Otherwise, use `st_size + 1`.
+     */
+    buf_len = stat.st_size ? stat.st_size + 1 : 32;
     for (;;) {
-        char *newbuf = wasm_runtime_malloc((uint32)len);
+        size_t bytes_read = 0;
+        char *buf;
 
-        if (newbuf == NULL) {
-            if (buf)
-                wasm_runtime_free(buf);
+        buf = wasm_runtime_malloc((uint32)buf_len);
+        if (buf == NULL) {
             *out_buf = NULL;
             return __WASI_ENOMEM;
         }
 
-        if (buf != NULL) {
-            bh_memcpy_s(newbuf, (uint32)len, buf, (uint32)len_org);
-            wasm_runtime_free(buf);
-        }
-
-        buf = newbuf;
-        size_t bytes_read = 0;
-        __wasi_errno_t error =
-            os_readlinkat(handle, path, buf, len, &bytes_read);
+        error = os_readlinkat(handle, path, buf, buf_len, &bytes_read);
         if (error != __WASI_ESUCCESS) {
             wasm_runtime_free(buf);
+            *p_len = 0;
             *out_buf = NULL;
             return error;
         }
-        if ((size_t)bytes_read + 1 < len) {
+
+        /* not truncated */
+        if (bytes_read < buf_len) {
             buf[bytes_read] = '\0';
-            *p_len = len;
+            *p_len = bytes_read + 1;
             *out_buf = buf;
-
             return __WASI_ESUCCESS;
         }
-        len_org = len;
-        len *= 2;
+
+        /* truncated, try again with a bigger buf */
+        wasm_runtime_free(buf);
+        buf = NULL;
+        buf_len *= 2;
     }
 }
 

+ 1 - 1
samples/file/wasm-app/main.c

@@ -18,7 +18,7 @@
 #define WORLD_OFFSET 7
 #define NAME_REPLACMENT "James"
 #define NAME_REPLACMENT_LEN (sizeof(NAME_REPLACMENT) - 1)
-#define ADDITIONAL_SPACE 1 * 1024 * 1024
+#define ADDITIONAL_SPACE 16 * 1024
 
 int
 main(int argc, char **argv)