Skip to content

Unix.utimes on a missing file results in EUKNOWNERR instead of ENOENT on Win32 #8857

@aantron

Description

@aantron

I believe this is caused by this code

hFile = CreateFile(wpath,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
caml_leave_blocking_section();
caml_stat_free(wpath);
if (hFile == INVALID_HANDLE_VALUE) {
win32_maperr(GetLastError());
uerror("utimes", path);
}

As you can see, caml_leave_blocking_section is called after CreateFile, but before GetLastError.

caml_leave_blocking_section preserves errno, but not the Win32 error code accessed by GetLastError/SetLastError:

ocaml/runtime/signals.c

Lines 177 to 182 in 301e1e6

CAMLexport void caml_leave_blocking_section(void)
{
int saved_errno;
/* Save the value of errno (PR#5982). */
saved_errno = errno;
caml_leave_blocking_section_hook ();

caml_leave_blocking_section_hook calls st_tls_get:

static void caml_thread_leave_blocking_section(void)
{
/* Wait until the runtime is free */
st_masterlock_acquire(&caml_master_lock);
/* Update curr_thread to point to the thread descriptor corresponding
to the thread currently executing */
curr_thread = st_tls_get(thread_descriptor_key);
/* Restore the runtime state from the curr_thread descriptor */
caml_thread_restore_runtime_state();
}

On Windows, this calls TlsGetValue:

static INLINE void * st_tls_get(st_tlskey k)
{
return TlsGetValue(k);
}

TlsGetValue clobbers the error code that would be returned by GetLastError.

cc @dra27

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions