From 08ddbd6ce024e1bee9a11d61f52dc0e3b753c616 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 21 May 2020 22:38:06 +0200
Subject: [PATCH 1/3] prepare Dlsym system for dynamic symbols on Windows

---
 src/shims/dlsym.rs                 | 19 ++++++++++++++-----
 src/shims/foreign_items/posix.rs   |  4 +---
 src/shims/foreign_items/windows.rs | 11 ++++++++---
 3 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs
index 3c4a942b59..1416db346c 100644
--- a/src/shims/dlsym.rs
+++ b/src/shims/dlsym.rs
@@ -11,12 +11,21 @@ pub enum Dlsym {
 impl Dlsym {
     // Returns an error for unsupported symbols, and None if this symbol
     // should become a NULL pointer (pretend it does not exist).
-    pub fn from_str(name: &str) -> InterpResult<'static, Option<Dlsym>> {
+    pub fn from_str(name: &[u8], target_os: &str) -> InterpResult<'static, Option<Dlsym>> {
         use self::Dlsym::*;
-        Ok(match name {
-            "getentropy" => Some(GetEntropy),
-            "__pthread_get_minstack" => None,
-            _ => throw_unsup_format!("unsupported dlsym: {}", name),
+        let name = String::from_utf8_lossy(name);
+        Ok(match target_os {
+            "linux" | "macos" => match &*name {
+                "getentropy" => Some(GetEntropy),
+                "__pthread_get_minstack" => None,
+                _ => throw_unsup_format!("unsupported dlsym: {}", name),
+            }
+            "windows" => match &*name {
+                "SetThreadStackGuarantee" => None,
+                "AcquireSRWLockExclusive" => None,
+                _ => throw_unsup_format!("unsupported dlsym: {}", name),
+            }
+            os => bug!("dlsym not implemented for target_os {}", os),
         })
     }
 }
diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs
index 951a40293b..39b00feec1 100644
--- a/src/shims/foreign_items/posix.rs
+++ b/src/shims/foreign_items/posix.rs
@@ -173,9 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
                 this.read_scalar(handle)?.not_undef()?;
                 let symbol = this.read_scalar(symbol)?.not_undef()?;
                 let symbol_name = this.memory.read_c_str(symbol)?;
-                let err = format!("bad c unicode symbol: {:?}", symbol_name);
-                let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
-                if let Some(dlsym) = Dlsym::from_str(symbol_name)? {
+                if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target.target_os)? {
                     let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
                     this.write_scalar(Scalar::from(ptr), dest)?;
                 } else {
diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs
index 7f3cd03cd2..a11e3b8aa6 100644
--- a/src/shims/foreign_items/windows.rs
+++ b/src/shims/foreign_items/windows.rs
@@ -260,9 +260,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
             }
             "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
                 #[allow(non_snake_case)]
-                let &[_hModule, _lpProcName] = check_arg_count(args)?;
-                // Pretend this does not exist / nothing happened, by returning zero.
-                this.write_null(dest)?;
+                let &[_hModule, lpProcName] = check_arg_count(args)?;
+                let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?;
+                if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? {
+                    let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
+                    this.write_scalar(Scalar::from(ptr), dest)?;
+                } else {
+                    this.write_null(dest)?;
+                }
             }
             "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
                 #[allow(non_snake_case)]

From f09decb398f86ebfb7938b5aca39202acb50d45e Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 21 May 2020 23:00:59 +0200
Subject: [PATCH 2/3] disentangle macos and linux dlsyms

---
 src/shims/dlsym.rs | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs
index 1416db346c..3016870928 100644
--- a/src/shims/dlsym.rs
+++ b/src/shims/dlsym.rs
@@ -15,15 +15,18 @@ impl Dlsym {
         use self::Dlsym::*;
         let name = String::from_utf8_lossy(name);
         Ok(match target_os {
-            "linux" | "macos" => match &*name {
-                "getentropy" => Some(GetEntropy),
+            "linux" => match &*name {
                 "__pthread_get_minstack" => None,
-                _ => throw_unsup_format!("unsupported dlsym: {}", name),
+                _ => throw_unsup_format!("unsupported Linux dlsym: {}", name),
+            }
+            "macos" => match &*name {
+                "getentropy" => Some(GetEntropy),
+                _ => throw_unsup_format!("unsupported macOS dlsym: {}", name),
             }
             "windows" => match &*name {
                 "SetThreadStackGuarantee" => None,
                 "AcquireSRWLockExclusive" => None,
-                _ => throw_unsup_format!("unsupported dlsym: {}", name),
+                _ => throw_unsup_format!("unsupported Windows dlsym: {}", name),
             }
             os => bug!("dlsym not implemented for target_os {}", os),
         })

From 526fae75413392dcfd05256145c5503011d9c89a Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 21 May 2020 23:06:31 +0200
Subject: [PATCH 3/3] GetProcAddress: basic validation for hModule argument

---
 src/shims/foreign_items/windows.rs | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs
index a11e3b8aa6..60448406a6 100644
--- a/src/shims/foreign_items/windows.rs
+++ b/src/shims/foreign_items/windows.rs
@@ -206,6 +206,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
 
+            // Dynamic symbol loading
+            "GetProcAddress" => {
+                #[allow(non_snake_case)]
+                let &[hModule, lpProcName] = check_arg_count(args)?;
+                this.read_scalar(hModule)?.not_undef()?;
+                let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?;
+                if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? {
+                    let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
+                    this.write_scalar(Scalar::from(ptr), dest)?;
+                } else {
+                    this.write_null(dest)?;
+                }
+            }
+
             // Miscellaneous
             "SystemFunction036" => {
                 // The actual name of 'RtlGenRandom'
@@ -258,17 +272,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
                 // Pretend this does not exist / nothing happened, by returning zero.
                 this.write_null(dest)?;
             }
-            "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
-                #[allow(non_snake_case)]
-                let &[_hModule, lpProcName] = check_arg_count(args)?;
-                let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?;
-                if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? {
-                    let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
-                    this.write_scalar(Scalar::from(ptr), dest)?;
-                } else {
-                    this.write_null(dest)?;
-                }
-            }
             "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
                 #[allow(non_snake_case)]
                 let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?;