From 71dccf8706ab25f75667c1cbb85ce94f2decbb57 Mon Sep 17 00:00:00 2001
From: Tobias Bucher <tobiasbucher5991@gmail.com>
Date: Thu, 19 Nov 2015 18:01:11 +0000
Subject: [PATCH] Also check for NULs in environment variables

This check is necessary, because the underlying API only reads strings
until the first NUL.
---
 src/libstd/sys/windows/fs.rs  | 13 +++----------
 src/libstd/sys/windows/mod.rs | 15 +++++++++++----
 src/libstd/sys/windows/os.rs  | 10 ++++++----
 3 files changed, 20 insertions(+), 18 deletions(-)

diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 31e0949edec..9db7ab53459 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -22,7 +22,8 @@ use sync::Arc;
 use sys::handle::Handle;
 use sys::{c, cvt};
 use sys_common::FromInner;
-use vec::Vec;
+
+use super::to_u16s;
 
 pub struct File { handle: Handle }
 
@@ -377,15 +378,6 @@ impl fmt::Debug for File {
     }
 }
 
-pub fn to_u16s(s: &Path) -> io::Result<Vec<u16>> {
-    let mut maybe_result = s.as_os_str().encode_wide().collect();
-    if maybe_result.iter().any(|&u| u == 0) {
-        return Err(io::Error::new(io::ErrorKind::InvalidInput, "paths cannot contain NULs"));
-    }
-    maybe_result.push(0);
-    Ok(maybe_result)
-}
-
 impl FileAttr {
     pub fn size(&self) -> u64 {
         ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64)
@@ -622,6 +614,7 @@ fn directory_junctions_are_directories() {
     use ffi::OsStr;
     use env;
     use rand::{self, StdRng, Rng};
+    use vec::Vec;
 
     macro_rules! t {
         ($e:expr) => (match $e {
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 3f76218eafe..7e5342a3fd4 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -72,10 +72,17 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
     }
 }
 
-fn to_utf16_os(s: &OsStr) -> Vec<u16> {
-    let mut v: Vec<_> = s.encode_wide().collect();
-    v.push(0);
-    v
+pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
+    fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
+        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
+        if maybe_result.iter().any(|&u| u == 0) {
+            return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                      "strings passed to WinAPI cannot contain NULs"));
+        }
+        maybe_result.push(0);
+        Ok(maybe_result)
+    }
+    inner(s.as_ref())
 }
 
 // Many Windows APIs follow a pattern of where we hand a buffer and then they
diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs
index 52740b2cad4..e2d2dc1a4de 100644
--- a/src/libstd/sys/windows/os.rs
+++ b/src/libstd/sys/windows/os.rs
@@ -28,6 +28,8 @@ use slice;
 use sys::{c, cvt};
 use sys::handle::Handle;
 
+use super::to_u16s;
+
 pub fn errno() -> i32 {
     unsafe { c::GetLastError() as i32 }
 }
@@ -228,7 +230,7 @@ pub fn chdir(p: &path::Path) -> io::Result<()> {
 }
 
 pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    let k = super::to_utf16_os(k);
+    let k = try!(to_u16s(k));
     let res = super::fill_utf16_buf(|buf, sz| unsafe {
         c::GetEnvironmentVariableW(k.as_ptr(), buf, sz)
     }, |buf| {
@@ -247,8 +249,8 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
 }
 
 pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
-    let k = super::to_utf16_os(k);
-    let v = super::to_utf16_os(v);
+    let k = try!(to_u16s(k));
+    let v = try!(to_u16s(v));
 
     cvt(unsafe {
         c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())
@@ -256,7 +258,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
 }
 
 pub fn unsetenv(n: &OsStr) -> io::Result<()> {
-    let v = super::to_utf16_os(n);
+    let v = try!(to_u16s(n));
     cvt(unsafe {
         c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())
     }).map(|_| ())