Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ add_executable(wibo
dll/ntdll.cpp
dll/ole32.cpp
dll/rpcrt4.cpp
dll/shlwapi.cpp
dll/user32.cpp
dll/vcruntime.cpp
dll/version.cpp
Expand Down Expand Up @@ -376,6 +377,8 @@ wibo_codegen_module(NAME entry HEADERS src/entry.h)
wibo_codegen_module(NAME mscoree HEADERS dll/mscoree.h)
wibo_codegen_module(NAME version HEADERS dll/version.h)
wibo_codegen_module(NAME rpcrt4 HEADERS dll/rpcrt4.h)
wibo_codegen_module(NAME shlwapi HEADERS dll/shlwapi.h)
wibo_codegen_module(NAME ws2 HEADERS dll/ws2.h)
wibo_codegen_module(NAME vcruntime HEADERS dll/vcruntime.h)
wibo_codegen_module(NAME lmgr HEADERS dll/lmgr.h)
wibo_codegen_module(NAME ole32 HEADERS dll/ole32.h)
Expand Down Expand Up @@ -475,6 +478,8 @@ if (WIBO_ENABLE_FIXTURE_TESTS)
wibo_add_fixture_bin(NAME test_dll_attach_failure SOURCES test/test_dll_attach_failure.c)
wibo_add_fixture_bin(NAME test_thread_notifications SOURCES test/test_thread_notifications.c)
wibo_add_fixture_bin(NAME test_bcrypt SOURCES test/test_bcrypt.c COMPILE_OPTIONS -lbcrypt)
wibo_add_fixture_bin(NAME test_shlwapi SOURCES test/test_shlwapi.c COMPILE_OPTIONS -lshlwapi)
wibo_add_fixture_bin(NAME test_ws2 SOURCES test/test_ws2.c COMPILE_OPTIONS -lws2_32)
wibo_add_fixture_bin(NAME test_resources SOURCES test/test_resources.c ${WIBO_TEST_BIN_DIR}/test_resources_res.o COMPILE_OPTIONS -lversion)
wibo_add_fixture_bin(NAME test_threading SOURCES test/test_threading.c)
wibo_add_fixture_bin(NAME test_tls SOURCES test/test_tls.c)
Expand Down
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build stage
FROM alpine:latest AS build
FROM alpine:latest AS dependencies

# Install dependencies
RUN apk add --no-cache \
Expand All @@ -19,6 +19,8 @@ RUN apk add --no-cache \
ninja \
python3

FROM dependencies AS build

# Copy source files
WORKDIR /wibo
COPY . /wibo
Expand Down
4 changes: 3 additions & 1 deletion Dockerfile.ubuntu
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build stage
FROM ubuntu:24.04 AS build
FROM ubuntu:24.04 AS dependencies

# Install dependencies
ENV DEBIAN_FRONTEND=noninteractive
Expand Down Expand Up @@ -30,6 +30,8 @@ RUN apt-get update \
wget \
&& rm -rf /var/lib/apt/lists/*

FROM dependencies AS build

# Copy source files
WORKDIR /wibo
COPY . /wibo
Expand Down
10 changes: 10 additions & 0 deletions dll/kernel32/handleapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,14 @@ BOOL WINAPI CloseHandle(HANDLE hObject) {
return TRUE;
}

BOOL WINAPI SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("SetHandleInformation(%p, 0x%x, 0x%x)\n", hObject, dwMask, dwFlags);
if (!wibo::handles().setInformation(hObject, dwMask, dwFlags)) {
setLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
return TRUE;
}

} // namespace kernel32
1 change: 1 addition & 0 deletions dll/kernel32/handleapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace kernel32 {

BOOL WINAPI CloseHandle(HANDLE hObject);
BOOL WINAPI SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags);
BOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle,
LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);

Expand Down
44 changes: 44 additions & 0 deletions dll/shlwapi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "shlwapi.h"

#include "common.h"
#include "context.h"
#include "kernel32/minwinbase.h"
#include "modules.h"

#include <cstring>

namespace shlwapi {

LPSTR WINAPI PathAddBackslashA(LPSTR pszPath) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("PathAddBackslashA(%s)\n", pszPath ? pszPath : "(null)");
if (!pszPath) {
return nullptr;
}

size_t length = std::strlen(pszPath);
if (length > 0 && pszPath[length - 1] == '\\') {
return pszPath + length;
}

if (length + 1 >= MAX_PATH) {
return nullptr;
}

pszPath[length] = '\\';
pszPath[length + 1] = '\0';
return pszPath + length + 1;
}

} // namespace shlwapi

#include "shlwapi_trampolines.h"

extern const wibo::ModuleStub lib_shlwapi = {
(const char *[]){
"shlwapi",
nullptr,
},
shlwapiThunkByName,
nullptr,
};
9 changes: 9 additions & 0 deletions dll/shlwapi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include "types.h"

namespace shlwapi {

LPSTR WINAPI PathAddBackslashA(LPSTR pszPath);

} // namespace shlwapi
151 changes: 149 additions & 2 deletions dll/ws2.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,157 @@
#include "ws2.h"

#include "common.h"
#include "context.h"
#include "modules.h"

#include <cstring>
#include <unistd.h>

namespace {

constexpr int SOCKET_ERROR = -1;
constexpr int WSAEFAULT = 10014;
constexpr int WSAHOST_NOT_FOUND = 11001;
constexpr int WSANOTINITIALISED = 10093;

thread_local int g_lastError = 0;
int g_startupCount = 0;

void setLastError(int error) { g_lastError = error; }

WORD makeVersion(BYTE major, BYTE minor) { return static_cast<WORD>(major | (minor << 8)); }

bool requireStarted() {
if (g_startupCount > 0) {
return true;
}
setLastError(WSANOTINITIALISED);
return false;
}

} // namespace

namespace ws2 {

int WINAPI WSAStartup(WORD wVersionRequired, WSADATA *lpWSAData) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("WSAStartup(0x%x, %p)\n", wVersionRequired, lpWSAData);
if (!lpWSAData) {
setLastError(WSAEFAULT);
return WSAEFAULT;
}

std::memset(lpWSAData, 0, sizeof(*lpWSAData));
lpWSAData->wVersion = wVersionRequired;
lpWSAData->wHighVersion = makeVersion(2, 2);
std::strncpy(lpWSAData->szDescription, "wibo fake Winsock", sizeof(lpWSAData->szDescription) - 1);
std::strncpy(lpWSAData->szSystemStatus, "Running", sizeof(lpWSAData->szSystemStatus) - 1);
lpWSAData->iMaxSockets = 0x7fff;
lpWSAData->iMaxUdpDg = 65467; // 65535 - max IPv4 header (60) - UDP header (8)

++g_startupCount;
setLastError(0);
return 0;
}

int WINAPI WSACleanup() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("WSACleanup()\n");
if (g_startupCount <= 0) {
setLastError(WSANOTINITIALISED);
return SOCKET_ERROR;
}

--g_startupCount;
setLastError(0);
return 0;
}

int WINAPI WSAGetLastError() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("WSAGetLastError() -> %d\n", g_lastError);
return g_lastError;
}

int WINAPI gethostname(LPSTR name, int namelen) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("gethostname(%p, %d)\n", name, namelen);
if (!requireStarted()) {
return SOCKET_ERROR;
}
if (!name || namelen <= 0) {
setLastError(WSAEFAULT);
return SOCKET_ERROR;
}

char host[256] = {};
if (::gethostname(host, sizeof(host) - 1) != 0 || host[0] == '\0') {
std::strncpy(host, "localhost", sizeof(host) - 1);
}

size_t length = std::strlen(host);
if (static_cast<size_t>(namelen) <= length) {
setLastError(WSAEFAULT);
return SOCKET_ERROR;
}

std::memcpy(name, host, length + 1);
setLastError(0);
return 0;
}

GUEST_PTR WINAPI gethostbyname(LPCSTR name) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("gethostbyname(%s)\n", name ? name : "(null)");
if (!requireStarted()) {
return GUEST_NULL;
}
setLastError(WSAHOST_NOT_FOUND);
return GUEST_NULL;
}

int WINAPI select(int nfds, LPVOID readfds, LPVOID writefds, LPVOID exceptfds, const void *timeout) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("select(%d, %p, %p, %p, %p)\n", nfds, readfds, writefds, exceptfds, timeout);
if (!requireStarted()) {
return SOCKET_ERROR;
}
(void)nfds;
(void)readfds;
(void)writefds;
(void)exceptfds;
(void)timeout;
setLastError(0);
return 0;
}

} // namespace ws2

#include "ws2_trampolines.h"

static void *resolveByOrdinal(uint16_t ordinal) {
// GHS 5.3.22 imports WS2_32.dll with the legacy winsock ordinal table.
// Keep these mappings tied to observed call sites rather than modern WS2_32 export ordinals.
switch (ordinal) {
case 18:
return (void *)thunk_ws2_select;
case 52:
return (void *)thunk_ws2_gethostbyname;
case 57:
return (void *)thunk_ws2_gethostname;
case 115:
return (void *)thunk_ws2_WSAStartup;
case 116:
return (void *)thunk_ws2_WSACleanup;
}
return nullptr;
}

extern const wibo::ModuleStub lib_ws2 = {
(const char *[]){
"WS2_32",
nullptr,
},
nullptr,
nullptr,
ws2ThunkByName,
resolveByOrdinal,
};
24 changes: 24 additions & 0 deletions dll/ws2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include "types.h"

struct WSADATA {
WORD wVersion;
WORD wHighVersion;
CHAR szDescription[257];
CHAR szSystemStatus[129];
WORD iMaxSockets;
WORD iMaxUdpDg;
GUEST_PTR lpVendorInfo;
};

namespace ws2 {

int WINAPI WSAStartup(WORD wVersionRequired, WSADATA *lpWSAData);
int WINAPI WSACleanup();
int WINAPI WSAGetLastError();
int WINAPI gethostname(LPSTR name, int namelen);
GUEST_PTR WINAPI gethostbyname(LPCSTR name);
int WINAPI select(int nfds, LPVOID readfds, LPVOID writefds, LPVOID exceptfds, const void *timeout);

} // namespace ws2
4 changes: 3 additions & 1 deletion src/modules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ extern const wibo::ModuleStub lib_ucrtbase;
extern const wibo::ModuleStub lib_ntdll;
extern const wibo::ModuleStub lib_rpcrt4;
extern const wibo::ModuleStub lib_ole32;
extern const wibo::ModuleStub lib_shlwapi;
extern const wibo::ModuleStub lib_user32;
extern const wibo::ModuleStub lib_vcruntime;
extern const wibo::ModuleStub lib_version;
Expand Down Expand Up @@ -203,7 +204,8 @@ LockedRegistry registry() {
reg.initialized = true;
const wibo::ModuleStub *builtins[] = {
&lib_advapi32, &lib_bcrypt, &lib_kernel32, &lib_lmgr, &lib_mscoree, &lib_ntdll,
&lib_ole32, &lib_rpcrt4, &lib_user32, &lib_vcruntime, &lib_version, &lib_ws2,
&lib_ole32, &lib_rpcrt4, &lib_shlwapi, &lib_user32, &lib_vcruntime, &lib_version,
&lib_ws2,
#if WIBO_HAS_MSVCRT
&lib_msvcrt,
#endif
Expand Down
9 changes: 9 additions & 0 deletions test/test_handleapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,21 @@ static void test_duplicate_handle_after_close(void) {
TEST_CHECK(dup == NULL);
}

static void test_set_handle_information_invalid_handle(void) {
HANDLE bogus = (HANDLE)(uintptr_t)0x1234;

SetLastError(0);
TEST_CHECK(!SetHandleInformation(bogus, HANDLE_FLAG_INHERIT, 0));
TEST_CHECK_EQ(ERROR_INVALID_HANDLE, GetLastError());
}

int main(void) {
test_duplicate_handle_basic();
test_duplicate_handle_close_source();
test_duplicate_handle_invalid_source();
test_duplicate_handle_invalid_target_process();
test_duplicate_pseudo_process_handle();
test_duplicate_handle_after_close();
test_set_handle_information_invalid_handle();
return EXIT_SUCCESS;
}
Loading
Loading