Commit 65299c37d1

m <m@pop-os.localdomain>
2022-02-11 20:11:23
validate in Windows using VirtualQuery
1 parent bd8d6a8
lib/std/c/darwin.zig
@@ -636,6 +636,12 @@ pub const MAP = struct {
     pub const FAILED = @intToPtr(*anyopaque, maxInt(usize));
 };
 
+pub const MSF = struct {
+    pub const ASYNC = 1;
+    pub const INVALIDATE = 2;
+    pub const SYNC = 4;
+};
+
 pub const SA = struct {
     /// take signal on signal stack
     pub const ONSTACK = 0x0001;
lib/std/c/dragonfly.zig
@@ -185,6 +185,12 @@ pub const MAP = struct {
     pub const SIZEALIGN = 262144;
 };
 
+pub const MSF = struct {
+    pub const ASYNC = 1;
+    pub const INVALIDATE = 2;
+    pub const SYNC = 4;
+};
+
 pub const W = struct {
     pub const NOHANG = 0x0001;
     pub const UNTRACED = 0x0002;
lib/std/c/freebsd.zig
@@ -410,6 +410,12 @@ pub const MAP = struct {
     pub const @"32BIT" = 0x00080000;
 };
 
+pub const MSF = struct {
+    pub const ASYNC = 1;
+    pub const INVALIDATE = 2;
+    pub const SYNC = 4;
+};
+
 pub const W = struct {
     pub const NOHANG = 1;
     pub const UNTRACED = 2;
lib/std/c/netbsd.zig
@@ -575,6 +575,12 @@ pub const MAP = struct {
     pub const STACK = 0x2000;
 };
 
+pub const MSF = struct {
+    pub const ASYNC = 1;
+    pub const INVALIDATE = 2;
+    pub const SYNC = 4;
+};
+
 pub const W = struct {
     pub const NOHANG = 0x00000001;
     pub const UNTRACED = 0x00000002;
lib/std/c/openbsd.zig
@@ -363,6 +363,12 @@ pub const MAP = struct {
     pub const CONCEAL = 0x8000;
 };
 
+pub const MSF = struct {
+    pub const ASYNC = 1;
+    pub const INVALIDATE = 2;
+    pub const SYNC = 4;
+};
+
 pub const W = struct {
     pub const NOHANG = 1;
     pub const UNTRACED = 2;
lib/std/c/solaris.zig
@@ -534,6 +534,12 @@ pub const MAP = struct {
     pub const INITDATA = 0x0800;
 };
 
+pub const MSF = struct {
+    pub const ASYNC = 1;
+    pub const INVALIDATE = 2;
+    pub const SYNC = 4;
+};
+
 pub const MADV = struct {
     /// no further special treatment
     pub const NORMAL = 0;
lib/std/os/windows/kernel32.zig
@@ -56,6 +56,7 @@ const LPOVERLAPPED_COMPLETION_ROUTINE = windows.LPOVERLAPPED_COMPLETION_ROUTINE;
 const UCHAR = windows.UCHAR;
 const FARPROC = windows.FARPROC;
 const INIT_ONCE_FN = windows.INIT_ONCE_FN;
+const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION;
 
 pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
 pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;
@@ -245,6 +246,7 @@ pub extern "kernel32" fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: ?*co
 
 pub extern "kernel32" fn VirtualAlloc(lpAddress: ?LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD) callconv(WINAPI) ?LPVOID;
 pub extern "kernel32" fn VirtualFree(lpAddress: ?LPVOID, dwSize: SIZE_T, dwFreeType: DWORD) callconv(WINAPI) BOOL;
+pub extern "kernel32" fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T) callconv(WINAPI) SIZE_T;
 
 pub extern "kernel32" fn LocalFree(hMem: HLOCAL) callconv(WINAPI) ?HLOCAL;
 
lib/std/os/linux.zig
@@ -412,8 +412,8 @@ pub const MSF = struct {
     pub const SYNC = 4;
 };
 
-pub fn msync(address: [*]const u8, length: usize, flags: u32) usize {
-    return syscall3(.msync, @ptrToInt(address), length, flags);
+pub fn msync(address: [*]const u8, length: usize, flags: i32) usize {
+    return syscall3(.msync, @ptrToInt(address), length, @bitCast(u32, flags));
 }
 
 pub fn munmap(address: [*]const u8, length: usize) usize {
lib/std/os/windows.zig
@@ -1495,6 +1495,19 @@ pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void {
     assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0);
 }
 
+pub const VirtualQuerryError = error{Unexpected};
+
+pub fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T) VirtualQuerryError!SIZE_T {
+    const rc = kernel32.VirtualQuery(lpAddress, lpBuffer, dwLength);
+    if (rc == 0) {
+        switch (kernel32.GetLastError()) {
+            else => |err| return unexpectedError(err),
+        }
+    }
+
+    return rc;
+}
+
 pub const SetConsoleTextAttributeError = error{Unexpected};
 
 pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void {
@@ -2586,6 +2599,11 @@ pub const CREATE_EVENT_MANUAL_RESET = 0x00000001;
 pub const EVENT_ALL_ACCESS = 0x1F0003;
 pub const EVENT_MODIFY_STATE = 0x0002;
 
+// MEMORY_BASIC_INFORMATION.Type flags for VirtualQuery
+pub const MEM_IMAGE = 0x1000000;
+pub const MEM_MAPPED = 0x40000;
+pub const MEM_PRIVATE = 0x20000;
+
 pub const PROCESS_INFORMATION = extern struct {
     hProcess: HANDLE,
     hThread: HANDLE,
@@ -2661,6 +2679,7 @@ pub const HEAP_NO_SERIALIZE = 0x00000001;
 // AllocationType values
 pub const MEM_COMMIT = 0x1000;
 pub const MEM_RESERVE = 0x2000;
+pub const MEM_FREE = 0x10000;
 pub const MEM_RESET = 0x80000;
 pub const MEM_RESET_UNDO = 0x1000000;
 pub const MEM_LARGE_PAGES = 0x20000000;
@@ -2960,6 +2979,19 @@ pub const COINIT = enum(c_int) {
     COINIT_SPEED_OVER_MEMORY = 8,
 };
 
+pub const MEMORY_BASIC_INFORMATION = extern struct {
+    BaseAddress: PVOID,
+    AllocationBase: PVOID,
+    AllocationProtect: DWORD,
+    PartitionId: WORD,
+    RegionSize: SIZE_T,
+    State: DWORD,
+    Protect: DWORD,
+    Type: DWORD,
+};
+
+pub const PMEMORY_BASIC_INFORMATION = *MEMORY_BASIC_INFORMATION;
+
 /// > The maximum path of 32,767 characters is approximate, because the "\\?\"
 /// > prefix may be expanded to a longer string by the system at run time, and
 /// > this expansion applies to the total length.
lib/std/debug.zig
@@ -424,24 +424,48 @@ pub const StackIterator = struct {
         return address;
     }
 
-    fn isValidMemory(address: u64) bool {
+    fn isValidMemory(address: usize) bool {
+        const aligned_address = address & ~@intCast(usize, (mem.page_size - 1));
+
+        // If the address does not span 2 pages, query only the first one
+        const length: usize = if (aligned_address == address) mem.page_size else 2 * mem.page_size;
+
+        const aligned_memory = @intToPtr([*]align(mem.page_size) u8, aligned_address)[0..length];
+
         if (native_os != .windows) {
-            var res = true;
-            const length = 2 * mem.page_size;
-            const aligned_address = address & ~@intCast(u64, (mem.page_size - 1));
-            const aligned_memory = @intToPtr([*]align(mem.page_size) u8, aligned_address)[0..length];
-
-            os.msync(aligned_memory, os.MSF.ASYNC) catch |err| {
-                switch (err) {
-                    os.MSyncError.UnmappedMemory => {
-                        res = false;
-                    },
-                    else => unreachable,
-                }
-            };
-            return res;
+            if (native_os != .wasi) {
+                os.msync(aligned_memory, os.MSF.ASYNC) catch |err| {
+                    switch (err) {
+                        os.MSyncError.UnmappedMemory => {
+                            return false;
+                        },
+                        else => unreachable,
+                    }
+                };
+            }
+
+            return true;
         } else {
-            // TODO: Using windows memory API check if a page is mapped
+            const w = os.windows;
+            var memory_info: w.MEMORY_BASIC_INFORMATION = undefined;
+            //const memory_info_ptr = @ptrCast(w.PMEMORY_BASIC_INFORMATION, buffer);
+
+            // The only error this function can throw is ERROR_INVALID_PARAMETER.
+            // supply an address that invalid i'll be thrown.
+            const rc = w.VirtualQuery(aligned_memory.ptr, &memory_info, aligned_memory.len) catch {
+                return false;
+            };
+
+            // Result code has to be bigger than zero (number of bytes written)
+            if (rc == 0) {
+                return false;
+            }
+
+            // Free pages cannot be read, they are unmapped
+            if (memory_info.State == w.MEM_FREE) {
+                return false;
+            }
+
             return true;
         }
     }