[ VM ] Fixed issue where error code was being clobbered by call to Dart_TypedDataReleaseData on Windows, resulting in OSError returning a 0 error instead of the true error code.

Bug: 2
Change-Id: I33e9319f57de73d9435936ddf853968834fb5a16
Reviewed-on: https://dart-review.googlesource.com/56461
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index 215cba3..4f89b2d 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -12,6 +12,7 @@
 #include "bin/log.h"
 #include "bin/namespace.h"
 #include "bin/typed_data_utils.h"
+#include "bin/utils.h"
 #include "include/dart_api.h"
 #include "platform/assert.h"
 
@@ -33,6 +34,7 @@
 void FUNCTION_NAME(Directory_SetCurrent)(Dart_NativeArguments args) {
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path = Dart_GetNativeArgument(args, 1);
+  OSError os_error;
   ASSERT(!Dart_IsError(path));
   bool result;
   {
@@ -40,11 +42,15 @@
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* name = data.GetCString();
     result = Directory::SetCurrent(namespc, name);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, true);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -53,36 +59,47 @@
   static const int kDoesNotExist = 0;
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path = Dart_GetNativeArgument(args, 1);
+  OSError os_error;
   Directory::ExistsResult result;
   {
     TypedDataScope data(path);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* name = data.GetCString();
     result = Directory::Exists(namespc, name);
+    if ((result != Directory::DOES_NOT_EXIST) ||
+        (result != Directory::EXISTS)) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result == Directory::EXISTS) {
     Dart_SetIntegerReturnValue(args, kExists);
   } else if (result == Directory::DOES_NOT_EXIST) {
     Dart_SetIntegerReturnValue(args, kDoesNotExist);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
 void FUNCTION_NAME(Directory_Create)(Dart_NativeArguments args) {
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path = Dart_GetNativeArgument(args, 1);
+  OSError os_error;
   bool result;
   {
     TypedDataScope data(path);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* name = data.GetCString();
     result = Directory::Create(namespc, name);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, true);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -95,23 +112,29 @@
 void FUNCTION_NAME(Directory_CreateTemp)(Dart_NativeArguments args) {
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path = Dart_GetNativeArgument(args, 1);
+  OSError os_error;
   const char* result = NULL;
   {
     TypedDataScope data(path);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* name = data.GetCString();
     result = Directory::CreateTemp(namespc, name);
+    if (result == NULL) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result != NULL) {
     Dart_SetReturnValue(args, DartUtils::NewString(result));
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
 void FUNCTION_NAME(Directory_Delete)(Dart_NativeArguments args) {
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path = Dart_GetNativeArgument(args, 1);
+  OSError os_error;
   bool result;
   {
     TypedDataScope data(path);
@@ -119,17 +142,22 @@
     const char* name = data.GetCString();
     result = Directory::Delete(namespc, name,
                                DartUtils::GetNativeBooleanArgument(args, 2));
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, true);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
 void FUNCTION_NAME(Directory_Rename)(Dart_NativeArguments args) {
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path = Dart_GetNativeArgument(args, 1);
+  OSError os_error;
   bool result;
   {
     TypedDataScope data(path);
@@ -137,11 +165,15 @@
     const char* name = data.GetCString();
     result = Directory::Rename(namespc, name,
                                DartUtils::GetNativeStringArgument(args, 2));
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, true);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index 383b6bb..115bf3f 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -88,6 +88,7 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
   File* file = NULL;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
@@ -102,11 +103,15 @@
     // files. Directories can be opened for reading using the posix
     // 'open' call.
     file = File::Open(namespc, filename, file_mode);
+    if (file == NULL) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (file != NULL) {
     Dart_SetIntegerReturnValue(args, reinterpret_cast<intptr_t>(file));
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -356,16 +361,21 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
   int64_t return_value;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* path = data.GetCString();
     return_value = File::LengthFromPath(namespc, path);
+    if (return_value < 0) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (return_value >= 0) {
     Dart_SetIntegerReturnValue(args, return_value);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -373,16 +383,21 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
   int64_t return_value;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* raw_name = data.GetCString();
     return_value = File::LastModified(namespc, raw_name);
+    if (return_value < 0) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (return_value >= 0) {
     Dart_SetIntegerReturnValue(args, return_value * kMillisecondsPerSecond);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -395,14 +410,19 @@
         "The second argument must be a 64-bit int."));
   }
   bool result;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* name = data.GetCString();
     result = File::SetLastModified(namespc, name, millis);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (!result) {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -410,16 +430,21 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
   int64_t return_value;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* name = data.GetCString();
     return_value = File::LastAccessed(namespc, name);
+    if (return_value < 0) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (return_value >= 0) {
     Dart_SetIntegerReturnValue(args, return_value * kMillisecondsPerSecond);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -432,14 +457,19 @@
         "The second argument must be a 64-bit int."));
   }
   bool result;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* name = data.GetCString();
     result = File::SetLastAccessed(namespc, name, millis);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (!result) {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -480,16 +510,21 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
   bool result;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* path = data.GetCString();
     result = File::Create(namespc, path);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, result);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -497,15 +532,20 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   bool result;
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* name = data.GetCString();
     const char* target = DartUtils::GetNativeStringArgument(args, 2);
     result = File::CreateLink(namespc, name, target);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (!result) {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -513,14 +553,19 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
   const char* target = NULL;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* name = data.GetCString();
     target = File::LinkTarget(namespc, name);
+    if (target == NULL) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (target == NULL) {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   } else {
     Dart_SetReturnValue(args, DartUtils::NewString(target));
   }
@@ -530,16 +575,21 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   bool result;
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* path = data.GetCString();
     result = File::Delete(namespc, path);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, result);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -547,16 +597,21 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
   bool result;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* path = data.GetCString();
     result = File::DeleteLink(namespc, path);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, result);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -564,17 +619,22 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle old_path_handle = Dart_GetNativeArgument(args, 1);
   bool result;
+  OSError os_error;
   {
     TypedDataScope old_path_data(old_path_handle);
     ASSERT(old_path_data.type() == Dart_TypedData_kUint8);
     const char* old_path = old_path_data.GetCString();
     const char* new_path = DartUtils::GetNativeStringArgument(args, 2);
     result = File::Rename(namespc, old_path, new_path);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, result);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -582,17 +642,22 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle old_path_handle = Dart_GetNativeArgument(args, 1);
   bool result;
+  OSError os_error;
   {
     TypedDataScope old_path_data(old_path_handle);
     ASSERT(old_path_data.type() == Dart_TypedData_kUint8);
     const char* old_path = old_path_data.GetCString();
     const char* new_path = DartUtils::GetNativeStringArgument(args, 2);
     result = File::RenameLink(namespc, old_path, new_path);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, result);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -600,17 +665,22 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle old_path_handle = Dart_GetNativeArgument(args, 1);
   bool result;
+  OSError os_error;
   {
     TypedDataScope old_path_data(old_path_handle);
     ASSERT(old_path_data.type() == Dart_TypedData_kUint8);
     const char* old_path = old_path_data.GetCString();
     const char* new_path = DartUtils::GetNativeStringArgument(args, 2);
     result = File::Copy(namespc, old_path, new_path);
+    if (!result) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (result) {
     Dart_SetBooleanReturnValue(args, result);
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -618,16 +688,21 @@
   Namespace* namespc = Namespace::GetNamespace(args, 0);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
   const char* path = NULL;
+  OSError os_error;
   {
     TypedDataScope data(path_handle);
     ASSERT(data.type() == Dart_TypedData_kUint8);
     const char* str = data.GetCString();
     path = File::GetCanonicalPath(namespc, str);
+    if (path == NULL) {
+      // Errors must be caught before TypedDataScope data is destroyed.
+      os_error.Reload();
+    }
   }
   if (path != NULL) {
     Dart_SetReturnValue(args, DartUtils::NewString(path));
   } else {
-    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
diff --git a/runtime/bin/utils.h b/runtime/bin/utils.h
index 234a969..8d4ab44 100644
--- a/runtime/bin/utils.h
+++ b/runtime/bin/utils.h
@@ -27,6 +27,8 @@
   }
   virtual ~OSError() { free(message_); }
 
+  void Reload();
+
   SubSystem sub_system() { return sub_system_; }
   int code() { return code_; }
   char* message() { return message_; }
diff --git a/runtime/bin/utils_android.cc b/runtime/bin/utils_android.cc
index a705997..d448efe 100644
--- a/runtime/bin/utils_android.cc
+++ b/runtime/bin/utils_android.cc
@@ -18,6 +18,10 @@
 namespace bin {
 
 OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
+  Reload();
+}
+
+void OSError::Reload() {
   set_sub_system(kSystem);
   set_code(errno);
   const int kBufferSize = 1024;
diff --git a/runtime/bin/utils_fuchsia.cc b/runtime/bin/utils_fuchsia.cc
index e1f3dca..ad6e418 100644
--- a/runtime/bin/utils_fuchsia.cc
+++ b/runtime/bin/utils_fuchsia.cc
@@ -17,6 +17,10 @@
 namespace bin {
 
 OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
+  Reload();
+}
+
+void OSError::Reload() {
   set_sub_system(kSystem);
   set_code(errno);
   const int kBufferSize = 1024;
diff --git a/runtime/bin/utils_linux.cc b/runtime/bin/utils_linux.cc
index 3e27c0c..6c7e9b7 100644
--- a/runtime/bin/utils_linux.cc
+++ b/runtime/bin/utils_linux.cc
@@ -18,6 +18,10 @@
 namespace bin {
 
 OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
+  Reload();
+}
+
+void OSError::Reload() {
   set_sub_system(kSystem);
   set_code(errno);
   const int kBufferSize = 1024;
diff --git a/runtime/bin/utils_macos.cc b/runtime/bin/utils_macos.cc
index bec7153..8d3ed43 100644
--- a/runtime/bin/utils_macos.cc
+++ b/runtime/bin/utils_macos.cc
@@ -21,6 +21,10 @@
 namespace bin {
 
 OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
+  Reload();
+}
+
+void OSError::Reload() {
   set_sub_system(kSystem);
   set_code(errno);
   const int kBufferSize = 1024;
diff --git a/runtime/bin/utils_win.cc b/runtime/bin/utils_win.cc
index 99e9fb8..bc5f934 100644
--- a/runtime/bin/utils_win.cc
+++ b/runtime/bin/utils_win.cc
@@ -32,6 +32,10 @@
 }
 
 OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
+  Reload();
+}
+
+void OSError::Reload() {
   set_code(GetLastError());
 
   static const int kMaxMessageLength = 256;