Merge changes I8c6b2d1d,I06e0f759,I95d79809

* changes:
  Add async_safe_format_fd_va_list
  Fix normalize_path's handling of "/.."
  linker: fix invalid zip file handling
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index 5f22c74..207035a 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -424,13 +424,18 @@
   return buffer_len;
 }
 
-int async_safe_format_fd(int fd, const char* format, ...) {
+int async_safe_format_fd_va_list(int fd, const char* format, va_list args) {
   FdOutputStream os(fd);
+  out_vformat(os, format, args);
+  return os.total;
+}
+
+int async_safe_format_fd(int fd, const char* format, ...) {
   va_list args;
   va_start(args, format);
-  out_vformat(os, format, args);
+  int result = async_safe_format_fd_va_list(fd, format, args);
   va_end(args);
-  return os.total;
+  return result;
 }
 
 static int write_stderr(const char* tag, const char* msg) {
diff --git a/libc/async_safe/include/async_safe/log.h b/libc/async_safe/include/async_safe/log.h
index 415b48e..df68062 100644
--- a/libc/async_safe/include/async_safe/log.h
+++ b/libc/async_safe/include/async_safe/log.h
@@ -90,6 +90,7 @@
 int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format, va_list args);
 
 int async_safe_format_fd(int fd, const char* format , ...) __printflike(2, 3);
+int async_safe_format_fd_va_list(int fd, const char* format, va_list args);
 int async_safe_format_log(int pri, const char* tag, const char* fmt, ...) __printflike(3, 4);
 int async_safe_format_log_va_list(int pri, const char* tag, const char* fmt, va_list ap);
 int async_safe_write_log(int pri, const char* tag, const char* msg);
diff --git a/linker/linker.cpp b/linker/linker.cpp
index e1fe50f..277b823 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -918,8 +918,7 @@
 
   if (OpenArchiveFd(fd, "", handle) != 0) {
     // invalid zip-file (?)
-    CloseArchive(handle);
-    close(fd);
+    CloseArchive(*handle);
     return false;
   }
 
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 789d5c1..6b9aec9 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -98,8 +98,8 @@
           while (out_ptr > buf && *--out_ptr != '/') {
           }
           if (in_ptr[0] == 0) {
-            // retain '/'
-            out_ptr++;
+            // retain '/' (or write the initial '/' for "/..")
+            *out_ptr++ = '/';
           }
           continue;
         }
diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp
index dce223a..e406af5 100644
--- a/linker/tests/linker_utils_test.cpp
+++ b/linker/tests/linker_utils_test.cpp
@@ -58,6 +58,9 @@
   ASSERT_TRUE(normalize_path("/a/../../b", &output));
   ASSERT_EQ("/b", output);
 
+  ASSERT_TRUE(normalize_path("/..", &output));
+  ASSERT_EQ("/", output);
+
   output = "unchanged";
   ASSERT_FALSE(normalize_path("root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
   ASSERT_EQ("unchanged", output);