Skip to main content

miri/shims/windows/
foreign_items.rs

1use std::ffi::OsStr;
2use std::path::{self, Path, PathBuf};
3use std::{io, iter, str};
4
5use rustc_abi::{Align, Size};
6use rustc_middle::ty::Ty;
7use rustc_span::Symbol;
8use rustc_target::callconv::FnAbi;
9use rustc_target::spec::Env;
10
11use self::shims::windows::handle::{Handle, PseudoHandle};
12use crate::shims::os_str::bytes_to_os_str;
13use crate::shims::windows::*;
14use crate::*;
15
16pub fn is_dyn_sym(name: &str) -> bool {
17    // std does dynamic detection for these symbols
18    matches!(
19        name,
20        "SetThreadDescription" | "GetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle"
21    )
22}
23
24#[cfg(windows)]
25fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
26    // We are on Windows so we can simply let the host do this.
27    interp_ok(path::absolute(path))
28}
29
30#[cfg(unix)]
31#[expect(clippy::get_first, clippy::arithmetic_side_effects)]
32fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
33    use std::sync::LazyLock;
34
35    use rustc_data_structures::fx::FxHashSet;
36
37    // We are on Unix, so we need to implement parts of the logic ourselves. `path` will use `/`
38    // separators, and the result should also use `/`.
39    // See <https://chrisdenton.github.io/omnipath/Overview.html#absolute-win32-paths> for more
40    // information about Windows paths.
41    // This does not handle all corner cases correctly, see
42    // <https://github.com/rust-lang/miri/pull/4262#issuecomment-2792168853> for more cursed
43    // examples.
44    let bytes = path.as_os_str().as_encoded_bytes();
45    // If it starts with `//./` or `//?/` then this is a magic special path, we just leave it
46    // unchanged.
47    if bytes.get(0).copied() == Some(b'/')
48        && bytes.get(1).copied() == Some(b'/')
49        && matches!(bytes.get(2), Some(b'.' | b'?'))
50        && bytes.get(3).copied() == Some(b'/')
51    {
52        return interp_ok(Ok(path.into()));
53    };
54    let is_unc = bytes.starts_with(b"//");
55    // Special treatment for Windows' magic filenames: they are treated as being relative to `//./`.
56    static MAGIC_FILENAMES: LazyLock<FxHashSet<&'static str>> = LazyLock::new(|| {
57        FxHashSet::from_iter([
58            "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
59            "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
60        ])
61    });
62    if str::from_utf8(bytes).is_ok_and(|s| MAGIC_FILENAMES.contains(&*s.to_ascii_uppercase())) {
63        let mut result: Vec<u8> = b"//./".into();
64        result.extend(bytes);
65        return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
66    }
67    // Otherwise we try to do something kind of close to what Windows does, but this is probably not
68    // right in all cases.
69    let mut result: Vec<&[u8]> = vec![]; // will be a vector of components, joined by `/`.
70    let mut bytes = bytes; // the remaining bytes to process
71    let mut stop = false;
72    while !stop {
73        // Find next component, and advance `bytes`.
74        let mut component = match bytes.iter().position(|&b| b == b'/') {
75            Some(pos) => {
76                let (component, tail) = bytes.split_at(pos);
77                bytes = &tail[1..]; // remove the `/`.
78                component
79            }
80            None => {
81                // There's no more `/`.
82                stop = true;
83                let component = bytes;
84                bytes = &[];
85                component
86            }
87        };
88        // `NUL` and only `NUL` also gets changed to be relative to `//./` later in the path.
89        // (This changed with Windows 11; previously, all magic filenames behaved like this.)
90        // Also, this does not apply to UNC paths.
91        if !is_unc && component.eq_ignore_ascii_case(b"NUL") {
92            let mut result: Vec<u8> = b"//./".into();
93            result.extend(component);
94            return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
95        }
96        // Deal with `..` -- Windows handles this entirely syntactically.
97        if component == b".." {
98            // Remove previous component, unless we are at the "root" already, then just ignore the `..`.
99            let is_root = {
100                // Paths like `/C:`.
101                result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':'])
102            } || {
103                // Paths like `//server/share`
104                result.len() == 4 && matches!(result[0], []) && matches!(result[1], [])
105            };
106            if !is_root {
107                result.pop();
108            }
109            continue;
110        }
111        // Preserve this component.
112        // Strip trailing `.`, but preserve trailing `..`. But not for UNC paths!
113        let len = component.len();
114        if !is_unc && len >= 2 && component[len - 1] == b'.' && component[len - 2] != b'.' {
115            component = &component[..len - 1];
116        }
117        // Add this component to output.
118        result.push(component);
119    }
120    // Drive letters must be followed by a `/`.
121    if result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':']) {
122        result.push(&[]);
123    }
124    // Let the host `absolute` function do working-dir handling.
125    let result = result.join(&b'/');
126    interp_ok(path::absolute(bytes_to_os_str(&result)?))
127}
128
129impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
130pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
131    fn emulate_foreign_item_inner(
132        &mut self,
133        link_name: Symbol,
134        abi: &FnAbi<'tcx, Ty<'tcx>>,
135        args: &[OpTy<'tcx>],
136        dest: &MPlaceTy<'tcx>,
137    ) -> InterpResult<'tcx, EmulateItemResult> {
138        let this = self.eval_context_mut();
139
140        // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
141
142        // Windows API stubs.
143        // HANDLE = *mut c_void (formerly: isize)
144        // NTSTATUS = LONG = i32
145        // DWORD = ULONG = u32
146        // BOOL = i32
147        // BOOLEAN = u8
148        match link_name.as_str() {
149            // Environment related shims
150            "GetEnvironmentVariableW" => {
151                // FIXME: This does not have a direct test (#3179).
152                let [name, buf, size] = this.check_shim_sig(
153                    shim_sig!(extern "system" fn(*const _, *mut _, u32) -> u32),
154                    link_name,
155                    abi,
156                    args,
157                )?;
158                let result = this.GetEnvironmentVariableW(name, buf, size)?;
159                this.write_scalar(result, dest)?;
160            }
161            "SetEnvironmentVariableW" => {
162                // FIXME: This does not have a direct test (#3179).
163                let [name, value] = this.check_shim_sig(
164                    shim_sig!(extern "system" fn(*const _, *const _) -> winapi::BOOL),
165                    link_name,
166                    abi,
167                    args,
168                )?;
169                let result = this.SetEnvironmentVariableW(name, value)?;
170                this.write_scalar(result, dest)?;
171            }
172            "GetEnvironmentStringsW" => {
173                // FIXME: This does not have a direct test (#3179).
174                let [] = this.check_shim_sig(
175                    shim_sig!(extern "system" fn() -> *mut _),
176                    link_name,
177                    abi,
178                    args,
179                )?;
180                let result = this.GetEnvironmentStringsW()?;
181                this.write_pointer(result, dest)?;
182            }
183            "FreeEnvironmentStringsW" => {
184                // FIXME: This does not have a direct test (#3179).
185                let [env_block] = this.check_shim_sig(
186                    shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
187                    link_name,
188                    abi,
189                    args,
190                )?;
191                let result = this.FreeEnvironmentStringsW(env_block)?;
192                this.write_scalar(result, dest)?;
193            }
194            "GetCurrentDirectoryW" => {
195                // FIXME: This does not have a direct test (#3179).
196                let [size, buf] = this.check_shim_sig(
197                    shim_sig!(extern "system" fn(u32, *mut _) -> u32),
198                    link_name,
199                    abi,
200                    args,
201                )?;
202                let result = this.GetCurrentDirectoryW(size, buf)?;
203                this.write_scalar(result, dest)?;
204            }
205            "SetCurrentDirectoryW" => {
206                // FIXME: This does not have a direct test (#3179).
207                let [path] = this.check_shim_sig(
208                    shim_sig!(extern "system" fn(*const _) -> winapi::BOOL),
209                    link_name,
210                    abi,
211                    args,
212                )?;
213                let result = this.SetCurrentDirectoryW(path)?;
214                this.write_scalar(result, dest)?;
215            }
216            "GetUserProfileDirectoryW" => {
217                // FIXME: This does not have a direct test (#3179).
218                let [token, buf, size] = this.check_shim_sig(
219                    shim_sig!(extern "system" fn(winapi::HANDLE, *mut _, *mut _) -> winapi::BOOL),
220                    link_name,
221                    abi,
222                    args,
223                )?;
224                let result = this.GetUserProfileDirectoryW(token, buf, size)?;
225                this.write_scalar(result, dest)?;
226            }
227            "GetCurrentProcessId" => {
228                // FIXME: This does not have a direct test (#3179).
229                let [] = this.check_shim_sig(
230                    shim_sig!(extern "system" fn() -> u32),
231                    link_name,
232                    abi,
233                    args,
234                )?;
235                let result = this.GetCurrentProcessId()?;
236                this.write_scalar(result, dest)?;
237            }
238
239            // File related shims
240            "NtWriteFile" => {
241                let [
242                    handle,
243                    event,
244                    apc_routine,
245                    apc_context,
246                    io_status_block,
247                    buf,
248                    n,
249                    byte_offset,
250                    key,
251                ] = this.check_shim_sig(
252                    shim_sig!(
253                        extern "system" fn(
254                            winapi::HANDLE,
255                            winapi::HANDLE,
256                            *mut _,
257                            *mut _,
258                            *mut _,
259                            *mut _,
260                            u32,
261                            *mut _,
262                            *mut _,
263                        ) -> i32
264                    ),
265                    link_name,
266                    abi,
267                    args,
268                )?;
269                this.NtWriteFile(
270                    handle,
271                    event,
272                    apc_routine,
273                    apc_context,
274                    io_status_block,
275                    buf,
276                    n,
277                    byte_offset,
278                    key,
279                    dest,
280                )?;
281            }
282            "NtReadFile" => {
283                let [
284                    handle,
285                    event,
286                    apc_routine,
287                    apc_context,
288                    io_status_block,
289                    buf,
290                    n,
291                    byte_offset,
292                    key,
293                ] = this.check_shim_sig(
294                    shim_sig!(
295                        extern "system" fn(
296                            winapi::HANDLE,
297                            winapi::HANDLE,
298                            *mut _,
299                            *mut _,
300                            *mut _,
301                            *mut _,
302                            u32,
303                            *mut _,
304                            *mut _,
305                        ) -> i32
306                    ),
307                    link_name,
308                    abi,
309                    args,
310                )?;
311                this.NtReadFile(
312                    handle,
313                    event,
314                    apc_routine,
315                    apc_context,
316                    io_status_block,
317                    buf,
318                    n,
319                    byte_offset,
320                    key,
321                    dest,
322                )?;
323            }
324            "GetFullPathNameW" => {
325                // FIXME: This does not have a direct test (#3179).
326                let [filename, size, buffer, filepart] = this.check_shim_sig(
327                    shim_sig!(extern "system" fn(*const _, u32, *mut _, *mut _) -> u32),
328                    link_name,
329                    abi,
330                    args,
331                )?;
332                this.check_no_isolation("`GetFullPathNameW`")?;
333
334                let filename = this.read_pointer(filename)?;
335                let size = this.read_scalar(size)?.to_u32()?;
336                let buffer = this.read_pointer(buffer)?;
337                let filepart = this.read_pointer(filepart)?;
338
339                if !this.ptr_is_null(filepart)? {
340                    throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
341                }
342
343                let filename = this.read_path_from_wide_str(filename)?;
344                let result = match win_get_full_path_name(&filename)? {
345                    Err(err) => {
346                        this.set_last_error(err)?;
347                        Scalar::from_u32(0) // return zero upon failure
348                    }
349                    Ok(abs_filename) => {
350                        Scalar::from_u32(helpers::windows_check_buffer_size(
351                            this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
352                        ))
353                        // This can in fact return 0. It is up to the caller to set last_error to 0
354                        // beforehand and check it afterwards to exclude that case.
355                    }
356                };
357                this.write_scalar(result, dest)?;
358            }
359            "CreateFileW" => {
360                let [
361                    file_name,
362                    desired_access,
363                    share_mode,
364                    security_attributes,
365                    creation_disposition,
366                    flags_and_attributes,
367                    template_file,
368                ] = this.check_shim_sig(
369                    shim_sig!(
370                        extern "system" fn(
371                            *const _,
372                            u32,
373                            u32,
374                            *mut _,
375                            u32,
376                            u32,
377                            winapi::HANDLE,
378                        ) -> winapi::HANDLE
379                    ),
380                    link_name,
381                    abi,
382                    args,
383                )?;
384                let handle = this.CreateFileW(
385                    file_name,
386                    desired_access,
387                    share_mode,
388                    security_attributes,
389                    creation_disposition,
390                    flags_and_attributes,
391                    template_file,
392                )?;
393                this.write_scalar(handle.to_scalar(this), dest)?;
394            }
395            "GetFileInformationByHandle" => {
396                let [handle, info] = this.check_shim_sig(
397                    shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
398                    link_name,
399                    abi,
400                    args,
401                )?;
402                let res = this.GetFileInformationByHandle(handle, info)?;
403                this.write_scalar(res, dest)?;
404            }
405            "SetFileInformationByHandle" => {
406                let [handle, class, info, size] = this.check_shim_sig(
407                    shim_sig!(
408                        extern "system" fn(
409                            winapi::HANDLE,
410                            winapi::FILE_INFO_BY_HANDLE_CLASS,
411                            *mut _,
412                            u32,
413                        ) -> winapi::BOOL
414                    ),
415                    link_name,
416                    abi,
417                    args,
418                )?;
419                let res = this.SetFileInformationByHandle(handle, class, info, size)?;
420                this.write_scalar(res, dest)?;
421            }
422            "FlushFileBuffers" => {
423                let [handle] = this.check_shim_sig(
424                    shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
425                    link_name,
426                    abi,
427                    args,
428                )?;
429                let res = this.FlushFileBuffers(handle)?;
430                this.write_scalar(res, dest)?;
431            }
432            "DeleteFileW" => {
433                let [file_name] = this.check_shim_sig(
434                    shim_sig!(extern "system" fn(*const _) -> winapi::BOOL),
435                    link_name,
436                    abi,
437                    args,
438                )?;
439                let res = this.DeleteFileW(file_name)?;
440                this.write_scalar(res, dest)?;
441            }
442            "SetFilePointerEx" => {
443                let [file, distance_to_move, new_file_pointer, move_method] = this.check_shim_sig(
444                    // i64 is actually a LARGE_INTEGER union of {u32, i32} and {i64}
445                    shim_sig!(extern "system" fn(winapi::HANDLE, i64, *mut _, u32) -> winapi::BOOL),
446                    link_name,
447                    abi,
448                    args,
449                )?;
450                let res =
451                    this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
452                this.write_scalar(res, dest)?;
453            }
454
455            // Allocation
456            "HeapAlloc" => {
457                // FIXME: This does not have a direct test (#3179).
458                let [handle, flags, size] = this.check_shim_sig(
459                    shim_sig!(extern "system" fn(winapi::HANDLE, u32, usize) -> *mut _),
460                    link_name,
461                    abi,
462                    args,
463                )?;
464                this.read_target_isize(handle)?;
465                let flags = this.read_scalar(flags)?.to_u32()?;
466                let size = this.read_target_usize(size)?;
467                const HEAP_ZERO_MEMORY: u32 = 0x00000008;
468                let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
469                    AllocInit::Zero
470                } else {
471                    AllocInit::Uninit
472                };
473                // Alignment is twice the pointer size.
474                // Source: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc>
475                let align = this.tcx.pointer_size().bytes().strict_mul(2);
476                let ptr = this.allocate_ptr(
477                    Size::from_bytes(size),
478                    Align::from_bytes(align).unwrap(),
479                    MiriMemoryKind::WinHeap.into(),
480                    init,
481                )?;
482                this.write_pointer(ptr, dest)?;
483            }
484            "HeapFree" => {
485                // FIXME: This does not have a direct test (#3179).
486                let [handle, flags, ptr] = this.check_shim_sig(
487                    shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _) -> winapi::BOOL),
488                    link_name,
489                    abi,
490                    args,
491                )?;
492                this.read_target_isize(handle)?;
493                this.read_scalar(flags)?.to_u32()?;
494                let ptr = this.read_pointer(ptr)?;
495                // "This pointer can be NULL." It doesn't say what happens then, but presumably nothing.
496                // (https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapfree)
497                if !this.ptr_is_null(ptr)? {
498                    this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
499                }
500                this.write_scalar(Scalar::from_i32(1), dest)?;
501            }
502            "HeapReAlloc" => {
503                // FIXME: This does not have a direct test (#3179).
504                let [handle, flags, old_ptr, size] = this.check_shim_sig(
505                    shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _, usize) -> *mut _),
506                    link_name,
507                    abi,
508                    args,
509                )?;
510                this.read_target_isize(handle)?;
511                this.read_scalar(flags)?.to_u32()?;
512                let old_ptr = this.read_pointer(old_ptr)?;
513                let size = this.read_target_usize(size)?;
514                let align = this.tcx.pointer_size().bytes().strict_mul(2); // same as above
515                // The docs say that `old_ptr` must come from an earlier HeapAlloc or HeapReAlloc,
516                // so unlike C `realloc` we do *not* allow a NULL here.
517                // (https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heaprealloc)
518                let new_ptr = this.reallocate_ptr(
519                    old_ptr,
520                    None,
521                    Size::from_bytes(size),
522                    Align::from_bytes(align).unwrap(),
523                    MiriMemoryKind::WinHeap.into(),
524                    AllocInit::Uninit,
525                )?;
526                this.write_pointer(new_ptr, dest)?;
527            }
528            "LocalFree" => {
529                // FIXME: This does not have a direct test (#3179).
530                let [ptr] = this.check_shim_sig(
531                    shim_sig!(extern "system" fn(winapi::HLOCAL) -> winapi::HLOCAL),
532                    link_name,
533                    abi,
534                    args,
535                )?;
536                let ptr = this.read_pointer(ptr)?;
537                // "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL."
538                // (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree)
539                if !this.ptr_is_null(ptr)? {
540                    this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
541                }
542                this.write_null(dest)?;
543            }
544
545            // errno
546            "SetLastError" => {
547                let [error] = this.check_shim_sig(
548                    shim_sig!(extern "system" fn(u32) -> ()),
549                    link_name,
550                    abi,
551                    args,
552                )?;
553                let error = this.read_scalar(error)?;
554                this.set_last_error(error)?;
555            }
556            "GetLastError" => {
557                let [] = this.check_shim_sig(
558                    shim_sig!(extern "system" fn() -> u32),
559                    link_name,
560                    abi,
561                    args,
562                )?;
563                let last_error = this.get_last_error()?;
564                this.write_scalar(last_error, dest)?;
565            }
566            "RtlNtStatusToDosError" => {
567                let [status] = this.check_shim_sig(
568                    shim_sig!(extern "system" fn(i32) -> u32),
569                    link_name,
570                    abi,
571                    args,
572                )?;
573                let status = this.read_scalar(status)?.to_u32()?;
574                let err = match status {
575                    // STATUS_MEDIA_WRITE_PROTECTED => ERROR_WRITE_PROTECT
576                    0xC00000A2 => 19,
577                    // STATUS_FILE_INVALID => ERROR_FILE_INVALID
578                    0xC0000098 => 1006,
579                    // STATUS_DISK_FULL => ERROR_DISK_FULL
580                    0xC000007F => 112,
581                    // STATUS_IO_DEVICE_ERROR => ERROR_IO_DEVICE
582                    0xC0000185 => 1117,
583                    // STATUS_ACCESS_DENIED => ERROR_ACCESS_DENIED
584                    0xC0000022 => 5,
585                    // Anything without an error code => ERROR_MR_MID_NOT_FOUND
586                    _ => 317,
587                };
588                this.write_scalar(Scalar::from_i32(err), dest)?;
589            }
590
591            // Querying system information
592            "GetSystemInfo" => {
593                // FIXME: This does not have a direct test (#3179).
594                // Also called from `page_size` crate.
595                let [system_info] = this.check_shim_sig(
596                    shim_sig!(extern "system" fn(*mut _) -> ()),
597                    link_name,
598                    abi,
599                    args,
600                )?;
601                let system_info =
602                    this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
603                // Initialize with `0`.
604                this.write_bytes_ptr(
605                    system_info.ptr(),
606                    iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
607                )?;
608                // Set selected fields.
609                this.write_int_fields_named(
610                    &[
611                        ("dwPageSize", this.machine.page_size.into()),
612                        ("dwNumberOfProcessors", this.machine.num_cpus.into()),
613                    ],
614                    &system_info,
615                )?;
616            }
617
618            // Thread-local storage
619            "TlsAlloc" => {
620                // This just creates a key; Windows does not natively support TLS destructors.
621
622                // Create key and return it.
623                let [] = this.check_shim_sig(
624                    shim_sig!(extern "system" fn() -> u32),
625                    link_name,
626                    abi,
627                    args,
628                )?;
629                let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
630                this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
631            }
632            "TlsGetValue" => {
633                let [key] = this.check_shim_sig(
634                    shim_sig!(extern "system" fn(u32) -> *mut _),
635                    link_name,
636                    abi,
637                    args,
638                )?;
639                let key = u128::from(this.read_scalar(key)?.to_u32()?);
640                let active_thread = this.active_thread();
641                let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
642                this.write_scalar(ptr, dest)?;
643            }
644            "TlsSetValue" => {
645                let [key, new_ptr] = this.check_shim_sig(
646                    shim_sig!(extern "system" fn(u32, *mut _) -> winapi::BOOL),
647                    link_name,
648                    abi,
649                    args,
650                )?;
651                let key = u128::from(this.read_scalar(key)?.to_u32()?);
652                let active_thread = this.active_thread();
653                let new_data = this.read_scalar(new_ptr)?;
654                this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
655
656                // Return success (`1`).
657                this.write_int(1, dest)?;
658            }
659            "TlsFree" => {
660                let [key] = this.check_shim_sig(
661                    shim_sig!(extern "system" fn(u32) -> winapi::BOOL),
662                    link_name,
663                    abi,
664                    args,
665                )?;
666                let key = u128::from(this.read_scalar(key)?.to_u32()?);
667                this.machine.tls.delete_tls_key(key)?;
668
669                // Return success (`1`).
670                this.write_int(1, dest)?;
671            }
672
673            // Access to command-line arguments
674            "GetCommandLineW" => {
675                // FIXME: This does not have a direct test (#3179).
676                let [] = this.check_shim_sig(
677                    shim_sig!(extern "system" fn() -> *mut _),
678                    link_name,
679                    abi,
680                    args,
681                )?;
682                this.write_pointer(
683                    this.machine.cmd_line.expect("machine must be initialized"),
684                    dest,
685                )?;
686            }
687
688            // Time related shims
689            "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
690                // FIXME: This does not have a direct test (#3179).
691                let [filetime] = this.check_shim_sig(
692                    shim_sig!(extern "system" fn(*mut _) -> ()),
693                    link_name,
694                    abi,
695                    args,
696                )?;
697                this.GetSystemTimeAsFileTime(link_name.as_str(), filetime)?;
698            }
699            "QueryPerformanceCounter" => {
700                // FIXME: This does not have a direct test (#3179).
701                let [performance_count] = this.check_shim_sig(
702                    shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
703                    link_name,
704                    abi,
705                    args,
706                )?;
707                let result = this.QueryPerformanceCounter(performance_count)?;
708                this.write_scalar(result, dest)?;
709            }
710            "QueryPerformanceFrequency" => {
711                // FIXME: This does not have a direct test (#3179).
712                let [frequency] = this.check_shim_sig(
713                    shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
714                    link_name,
715                    abi,
716                    args,
717                )?;
718                let result = this.QueryPerformanceFrequency(frequency)?;
719                this.write_scalar(result, dest)?;
720            }
721            "Sleep" => {
722                // FIXME: This does not have a direct test (#3179).
723                let [timeout] = this.check_shim_sig(
724                    shim_sig!(extern "system" fn(u32) -> ()),
725                    link_name,
726                    abi,
727                    args,
728                )?;
729
730                this.Sleep(timeout)?;
731            }
732            "CreateWaitableTimerExW" => {
733                // FIXME: This does not have a direct test (#3179).
734                let [attributes, name, flags, access] = this.check_shim_sig(
735                    shim_sig!(extern "system" fn(*mut _, *const _, u32, u32) -> winapi::HANDLE),
736                    link_name,
737                    abi,
738                    args,
739                )?;
740                this.read_pointer(attributes)?;
741                this.read_pointer(name)?;
742                this.read_scalar(flags)?.to_u32()?;
743                this.read_scalar(access)?.to_u32()?;
744                // Unimplemented. Always return failure.
745                let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
746                this.set_last_error(not_supported)?;
747                this.write_null(dest)?;
748            }
749
750            // Synchronization primitives
751            "InitOnceBeginInitialize" => {
752                let [ptr, flags, pending, context] = this.check_shim_sig(
753                    shim_sig!(extern "system" fn(*mut _, u32, *mut _, *mut _) -> winapi::BOOL),
754                    link_name,
755                    abi,
756                    args,
757                )?;
758                this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
759            }
760            "InitOnceComplete" => {
761                let [ptr, flags, context] = this.check_shim_sig(
762                    shim_sig!(extern "system" fn(*mut _, u32, *mut _) -> winapi::BOOL),
763                    link_name,
764                    abi,
765                    args,
766                )?;
767                let result = this.InitOnceComplete(ptr, flags, context)?;
768                this.write_scalar(result, dest)?;
769            }
770            "WaitOnAddress" => {
771                // FIXME: This does not have a direct test (#3179).
772                let [ptr_op, compare_op, size_op, timeout_op] = this.check_shim_sig(
773                    // First pointer is volatile
774                    shim_sig!(extern "system" fn(*mut _, *mut _, usize, u32) -> winapi::BOOL),
775                    link_name,
776                    abi,
777                    args,
778                )?;
779
780                this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
781            }
782            "WakeByAddressSingle" => {
783                // FIXME: This does not have a direct test (#3179).
784                let [ptr_op] = this.check_shim_sig(
785                    shim_sig!(extern "system" fn(*mut _) -> ()),
786                    link_name,
787                    abi,
788                    args,
789                )?;
790
791                this.WakeByAddressSingle(ptr_op)?;
792            }
793            "WakeByAddressAll" => {
794                // FIXME: This does not have a direct test (#3179).
795                let [ptr_op] = this.check_shim_sig(
796                    shim_sig!(extern "system" fn(*mut _) -> ()),
797                    link_name,
798                    abi,
799                    args,
800                )?;
801
802                this.WakeByAddressAll(ptr_op)?;
803            }
804
805            // Dynamic symbol loading
806            "GetProcAddress" => {
807                // FIXME: This does not have a direct test (#3179).
808                let [module, proc_name] = this.check_shim_sig(
809                    shim_sig!(extern "system" fn(winapi::HMODULE, *const _) -> winapi::FARPROC),
810                    link_name,
811                    abi,
812                    args,
813                )?;
814                this.read_target_isize(module)?;
815                let name = this.read_c_str(this.read_pointer(proc_name)?)?;
816                if let Ok(name) = str::from_utf8(name)
817                    && is_dyn_sym(name)
818                {
819                    let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
820                    this.write_pointer(ptr, dest)?;
821                } else {
822                    this.write_null(dest)?;
823                }
824            }
825
826            // Threading
827            "CreateThread" => {
828                let [security, stacksize, start, arg, flags, thread] = this.check_shim_sig(
829                    shim_sig!(
830                        extern "system" fn(
831                            *mut _,
832                            usize,
833                            *mut _,
834                            *mut _,
835                            u32,
836                            *mut _,
837                        ) -> winapi::HANDLE
838                    ),
839                    link_name,
840                    abi,
841                    args,
842                )?;
843
844                let thread_id =
845                    this.CreateThread(security, stacksize, start, arg, flags, thread)?;
846
847                this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
848            }
849            "WaitForSingleObject" => {
850                let [handle, timeout] = this.check_shim_sig(
851                    shim_sig!(extern "system" fn(winapi::HANDLE, u32) -> u32),
852                    link_name,
853                    abi,
854                    args,
855                )?;
856
857                this.WaitForSingleObject(handle, timeout, dest)?;
858            }
859            "GetCurrentProcess" => {
860                let [] = this.check_shim_sig(
861                    shim_sig!(extern "system" fn() -> winapi::HANDLE),
862                    link_name,
863                    abi,
864                    args,
865                )?;
866
867                this.write_scalar(
868                    Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
869                    dest,
870                )?;
871            }
872            "GetCurrentThread" => {
873                let [] = this.check_shim_sig(
874                    shim_sig!(extern "system" fn() -> winapi::HANDLE),
875                    link_name,
876                    abi,
877                    args,
878                )?;
879
880                this.write_scalar(
881                    Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
882                    dest,
883                )?;
884            }
885            "SetThreadDescription" => {
886                let [handle, name] = this.check_shim_sig(
887                    shim_sig!(extern "system" fn(winapi::HANDLE, *const _) -> i32),
888                    link_name,
889                    abi,
890                    args,
891                )?;
892
893                let handle = this.read_handle(handle, "SetThreadDescription")?;
894                let name = this.read_wide_str(this.read_pointer(name)?)?;
895
896                let thread = match handle {
897                    Handle::Thread(thread) => thread,
898                    Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
899                    _ => this.invalid_handle("SetThreadDescription")?,
900                };
901                // FIXME: use non-lossy conversion
902                this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
903                this.write_scalar(Scalar::from_u32(0), dest)?;
904            }
905            "GetThreadDescription" => {
906                let [handle, name_ptr] = this.check_shim_sig(
907                    shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> i32),
908                    link_name,
909                    abi,
910                    args,
911                )?;
912
913                let handle = this.read_handle(handle, "GetThreadDescription")?;
914                let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; // the pointer where we should store the ptr to the name
915
916                let thread = match handle {
917                    Handle::Thread(thread) => thread,
918                    Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
919                    _ => this.invalid_handle("GetThreadDescription")?,
920                };
921                // Looks like the default thread name is empty.
922                let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
923                let name = this.alloc_os_str_as_wide_str(
924                    bytes_to_os_str(&name)?,
925                    MiriMemoryKind::WinLocal.into(),
926                )?;
927                let name = Scalar::from_maybe_pointer(name, this);
928                let res = Scalar::from_u32(0);
929
930                this.write_scalar(name, &name_ptr)?;
931                this.write_scalar(res, dest)?;
932            }
933            "GetThreadId" => {
934                let [handle] = this.check_shim_sig(
935                    shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
936                    link_name,
937                    abi,
938                    args,
939                )?;
940                let handle = this.read_handle(handle, "GetThreadId")?;
941                let thread = match handle {
942                    Handle::Thread(thread) => thread,
943                    Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
944                    _ => this.invalid_handle("GetThreadDescription")?,
945                };
946                let tid = this.get_tid(thread);
947                this.write_scalar(Scalar::from_u32(tid), dest)?;
948            }
949            "GetCurrentThreadId" => {
950                let [] = this.check_shim_sig(
951                    shim_sig!(extern "system" fn() -> u32),
952                    link_name,
953                    abi,
954                    args,
955                )?;
956                let thread = this.active_thread();
957                let tid = this.get_tid(thread);
958                this.write_scalar(Scalar::from_u32(tid), dest)?;
959            }
960
961            // Miscellaneous
962            "ExitProcess" => {
963                // FIXME: This does not have a direct test (#3179).
964                let [code] = this.check_shim_sig(
965                    shim_sig!(extern "system" fn(u32) -> ()),
966                    link_name,
967                    abi,
968                    args,
969                )?;
970                // Windows technically uses u32, but we unify everything to a Unix-style i32.
971                let code = this.read_scalar(code)?.to_i32()?;
972                throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
973            }
974            "SystemFunction036" => {
975                // used by getrandom 0.1
976                // This is really 'RtlGenRandom'.
977                let [ptr, len] = this.check_shim_sig(
978                    // Returns winapi::BOOLEAN, which is a byte
979                    shim_sig!(extern "system" fn(*mut _, u32) -> u8),
980                    link_name,
981                    abi,
982                    args,
983                )?;
984                let ptr = this.read_pointer(ptr)?;
985                let len = this.read_scalar(len)?.to_u32()?;
986                this.gen_random(ptr, len.into())?;
987                this.write_scalar(Scalar::from_bool(true), dest)?;
988            }
989            "ProcessPrng" => {
990                // FIXME: This does not have a direct test (#3179).
991                // used by `std`
992                let [ptr, len] = this.check_shim_sig(
993                    shim_sig!(extern "system" fn(*mut _, usize) -> winapi::BOOL),
994                    link_name,
995                    abi,
996                    args,
997                )?;
998                let ptr = this.read_pointer(ptr)?;
999                let len = this.read_target_usize(len)?;
1000                this.gen_random(ptr, len)?;
1001                this.write_int(1, dest)?;
1002            }
1003            "BCryptGenRandom" => {
1004                // used by getrandom 0.2
1005                let [algorithm, ptr, len, flags] = this.check_shim_sig(
1006                    shim_sig!(extern "system" fn(*mut _, *mut _, u32, u32) -> i32),
1007                    link_name,
1008                    abi,
1009                    args,
1010                )?;
1011                let algorithm = this.read_scalar(algorithm)?;
1012                let algorithm = algorithm.to_target_usize(this)?;
1013                let ptr = this.read_pointer(ptr)?;
1014                let len = this.read_scalar(len)?.to_u32()?;
1015                let flags = this.read_scalar(flags)?.to_u32()?;
1016                match flags {
1017                    0 => {
1018                        if algorithm != 0x81 {
1019                            // BCRYPT_RNG_ALG_HANDLE
1020                            throw_unsup_format!(
1021                                "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
1022                            );
1023                        }
1024                    }
1025                    2 => {
1026                        // BCRYPT_USE_SYSTEM_PREFERRED_RNG
1027                        if algorithm != 0 {
1028                            throw_unsup_format!(
1029                                "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
1030                            );
1031                        }
1032                    }
1033                    _ => {
1034                        throw_unsup_format!(
1035                            "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
1036                        );
1037                    }
1038                }
1039                this.gen_random(ptr, len.into())?;
1040                this.write_null(dest)?; // STATUS_SUCCESS
1041            }
1042            "GetConsoleScreenBufferInfo" => {
1043                // FIXME: This does not have a direct test (#3179).
1044                // `term` needs this, so we fake it.
1045                let [console, buffer_info] = this.check_shim_sig(
1046                    shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
1047                    link_name,
1048                    abi,
1049                    args,
1050                )?;
1051                this.read_target_isize(console)?;
1052                // FIXME: this should use deref_pointer_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std
1053                this.deref_pointer(buffer_info)?;
1054                // Indicate an error.
1055                // FIXME: we should set last_error, but to what?
1056                this.write_null(dest)?;
1057            }
1058            "GetStdHandle" => {
1059                // FIXME: This does not have a direct test (#3179).
1060                let [which] = this.check_shim_sig(
1061                    shim_sig!(extern "system" fn(u32) -> winapi::HANDLE),
1062                    link_name,
1063                    abi,
1064                    args,
1065                )?;
1066                let res = this.GetStdHandle(which)?;
1067                this.write_scalar(res, dest)?;
1068            }
1069            "DuplicateHandle" => {
1070                let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
1071                    this.check_shim_sig(
1072                        shim_sig!(
1073                            extern "system" fn(
1074                                winapi::HANDLE,
1075                                winapi::HANDLE,
1076                                winapi::HANDLE,
1077                                *mut _,
1078                                u32,
1079                                winapi::BOOL,
1080                                u32,
1081                            ) -> winapi::BOOL
1082                        ),
1083                        link_name,
1084                        abi,
1085                        args,
1086                    )?;
1087                let res = this.DuplicateHandle(
1088                    src_proc,
1089                    src_handle,
1090                    target_proc,
1091                    target_handle,
1092                    access,
1093                    inherit,
1094                    options,
1095                )?;
1096                this.write_scalar(res, dest)?;
1097            }
1098            "CloseHandle" => {
1099                let [handle] = this.check_shim_sig(
1100                    shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
1101                    link_name,
1102                    abi,
1103                    args,
1104                )?;
1105
1106                let ret = this.CloseHandle(handle)?;
1107
1108                this.write_scalar(ret, dest)?;
1109            }
1110            "GetModuleFileNameW" => {
1111                // FIXME: This does not have a direct test (#3179).
1112                let [handle, filename, size] = this.check_shim_sig(
1113                    shim_sig!(extern "system" fn(winapi::HMODULE, *mut _, u32) -> u32),
1114                    link_name,
1115                    abi,
1116                    args,
1117                )?;
1118                this.check_no_isolation("`GetModuleFileNameW`")?;
1119
1120                let handle = this.read_handle(handle, "GetModuleFileNameW")?;
1121                let filename = this.read_pointer(filename)?;
1122                let size = this.read_scalar(size)?.to_u32()?;
1123
1124                if handle != Handle::Null {
1125                    throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
1126                }
1127
1128                // Using the host current_exe is a bit off, but consistent with Linux
1129                // (where stdlib reads /proc/self/exe).
1130                let path = std::env::current_exe().unwrap();
1131                let (all_written, size_needed) =
1132                    this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
1133
1134                if all_written {
1135                    // If the function succeeds, the return value is the length of the string that
1136                    // is copied to the buffer, in characters, not including the terminating null
1137                    // character.
1138                    this.write_int(size_needed.strict_sub(1), dest)?;
1139                } else {
1140                    // If the buffer is too small to hold the module name, the string is truncated
1141                    // to nSize characters including the terminating null character, the function
1142                    // returns nSize, and the function sets the last error to
1143                    // ERROR_INSUFFICIENT_BUFFER.
1144                    this.write_int(size, dest)?;
1145                    let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
1146                    this.set_last_error(insufficient_buffer)?;
1147                }
1148            }
1149            "FormatMessageW" => {
1150                // FIXME: This does not have a direct test (#3179).
1151                let [flags, module, message_id, language_id, buffer, size, arguments] = this
1152                    .check_shim_sig(
1153                        shim_sig!(
1154                            extern "system" fn(u32, *const _, u32, u32, *mut _, u32, *mut _) -> u32
1155                        ),
1156                        link_name,
1157                        abi,
1158                        args,
1159                    )?;
1160
1161                let flags = this.read_scalar(flags)?.to_u32()?;
1162                let _module = this.read_pointer(module)?; // seems to contain a module name
1163                let message_id = this.read_scalar(message_id)?;
1164                let _language_id = this.read_scalar(language_id)?.to_u32()?;
1165                let buffer = this.read_pointer(buffer)?;
1166                let size = this.read_scalar(size)?.to_u32()?;
1167                let _arguments = this.read_pointer(arguments)?;
1168
1169                // We only support `FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS`
1170                // This also means `arguments` can be ignored.
1171                if flags != 4096u32 | 512u32 {
1172                    throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
1173                }
1174
1175                let error = this.try_errnum_to_io_error(message_id)?;
1176                let formatted = match error {
1177                    Some(err) => format!("{err}"),
1178                    None => format!("<unknown error in FormatMessageW: {message_id}>"),
1179                };
1180                let (complete, length) =
1181                    this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
1182                if !complete {
1183                    // The API docs don't say what happens when the buffer is not big enough...
1184                    // Let's just bail.
1185                    throw_unsup_format!("FormatMessageW: buffer not big enough");
1186                }
1187                // The return value is the number of characters stored *excluding* the null terminator.
1188                this.write_int(length.strict_sub(1), dest)?;
1189            }
1190
1191            "_Unwind_RaiseException" => {
1192                // FIXME: This does not have a direct test (#3179).
1193                // This is not formally part of POSIX, but it is very wide-spread on POSIX systems.
1194                // It was originally specified as part of the Itanium C++ ABI:
1195                // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw.
1196                // MinGW implements _Unwind_RaiseException on top of SEH exceptions.
1197                if this.tcx.sess.target.env != Env::Gnu {
1198                    throw_unsup_format!(
1199                        "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
1200                    );
1201                }
1202                // This function looks and behaves exactly like miri_start_unwind.
1203                let [payload] = this.check_shim_sig(
1204                    shim_sig!(extern "C" fn(*mut _) -> unwind::libunwind::_Unwind_Reason_Code),
1205                    link_name,
1206                    abi,
1207                    args,
1208                )?;
1209                this.handle_miri_start_unwind(payload)?;
1210                return interp_ok(EmulateItemResult::NeedsUnwind);
1211            }
1212
1213            // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
1214            // These shims are enabled only when the caller is in the standard library.
1215            "GetProcessHeap" if this.frame_in_std() => {
1216                let [] = this.check_shim_sig(
1217                    shim_sig!(extern "system" fn() -> winapi::HANDLE),
1218                    link_name,
1219                    abi,
1220                    args,
1221                )?;
1222                // Just fake a HANDLE
1223                // It's fine to not use the Handle type here because its a stub
1224                this.write_int(1, dest)?;
1225            }
1226            "GetModuleHandleA" if this.frame_in_std() => {
1227                let [_module_name] = this.check_shim_sig(
1228                    shim_sig!(extern "system" fn(*const _) -> winapi::HMODULE),
1229                    link_name,
1230                    abi,
1231                    args,
1232                )?;
1233                // We need to return something non-null here to make `compat_fn!` work.
1234                this.write_int(1, dest)?;
1235            }
1236            "SetConsoleTextAttribute" if this.frame_in_std() => {
1237                let [_console_output, _attribute] = this.check_shim_sig(
1238                    shim_sig!(extern "system" fn(winapi::HANDLE, u16) -> winapi::BOOL),
1239                    link_name,
1240                    abi,
1241                    args,
1242                )?;
1243                // Pretend these does not exist / nothing happened, by returning zero.
1244                this.write_null(dest)?;
1245            }
1246            "GetConsoleMode" if this.frame_in_std() => {
1247                let [console, mode] = this.check_shim_sig(
1248                    shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
1249                    link_name,
1250                    abi,
1251                    args,
1252                )?;
1253                this.read_target_isize(console)?;
1254                this.deref_pointer_as(mode, this.machine.layouts.u32)?;
1255                // Indicate an error.
1256                this.write_null(dest)?;
1257            }
1258            "GetFileType" if this.frame_in_std() => {
1259                let [_file] = this.check_shim_sig(
1260                    shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
1261                    link_name,
1262                    abi,
1263                    args,
1264                )?;
1265                // Return unknown file type.
1266                this.write_null(dest)?;
1267            }
1268            "AddVectoredExceptionHandler" if this.frame_in_std() => {
1269                let [_first, _handler] = this.check_shim_sig(
1270                    shim_sig!(extern "system" fn(u32, *mut _) -> *mut _),
1271                    link_name,
1272                    abi,
1273                    args,
1274                )?;
1275                // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
1276                this.write_int(1, dest)?;
1277            }
1278            "SetThreadStackGuarantee" if this.frame_in_std() => {
1279                let [_stack_size_in_bytes] = this.check_shim_sig(
1280                    shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
1281                    link_name,
1282                    abi,
1283                    args,
1284                )?;
1285                // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
1286                this.write_int(1, dest)?;
1287            }
1288            // this is only callable from std because we know that std ignores the return value
1289            "SwitchToThread" if this.frame_in_std() => {
1290                let [] = this.check_shim_sig(
1291                    shim_sig!(extern "system" fn() -> winapi::BOOL),
1292                    link_name,
1293                    abi,
1294                    args,
1295                )?;
1296
1297                this.yield_active_thread();
1298
1299                // FIXME: this should return a nonzero value if this call does result in switching to another thread.
1300                this.write_null(dest)?;
1301            }
1302
1303            _ => return interp_ok(EmulateItemResult::NotSupported),
1304        }
1305
1306        interp_ok(EmulateItemResult::NeedsReturn)
1307    }
1308}