Skip to content

Commit

Permalink
windows: random things (oven-sh#9046)
Browse files Browse the repository at this point in the history
* random things

* fix reliability of loading napi stuff

* fix posix build

* a
  • Loading branch information
paperclover authored and nikeee committed Feb 28, 2024
1 parent 6b3da2c commit 0994132
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 38 deletions.
1 change: 0 additions & 1 deletion src/bun.js/RuntimeTranspilerCache.zig
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ pub const RuntimeTranspilerCache = struct {
.utf8 => Encoding.utf8,
.utf16 => Encoding.utf16,
.latin1 => Encoding.latin1,
else => @panic("Unexpected encoding"),
},
},
.sourcemap_byte_length = sourcemap.len,
Expand Down
15 changes: 11 additions & 4 deletions src/bun.js/bindings/BunProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,10 @@ JSC_DEFINE_CUSTOM_SETTER(Process_defaultSetter,
}

extern "C" bool Bun__resolveEmbeddedNodeFile(void*, BunString*);
#if OS(WINDOWS)
extern "C" HMODULE Bun__LoadLibraryBunString(BunString*);
#endif

JSC_DECLARE_HOST_FUNCTION(Process_functionDlopen);
JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen,
(JSC::JSGlobalObject * globalObject_, JSC::CallFrame* callFrame))
{
Expand Down Expand Up @@ -291,16 +293,21 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen,

RETURN_IF_EXCEPTION(scope, {});
#if OS(WINDOWS)
CString utf8 = filename.utf8();
HMODULE handle = LoadLibraryA(utf8.data());
BunString filename_str = Bun::toString(filename);
HMODULE handle = Bun__LoadLibraryBunString(&filename_str);
#else
CString utf8 = filename.utf8();
void* handle = dlopen(utf8.data(), RTLD_LAZY);
#endif

if (!handle) {
#if OS(WINDOWS)
WTF::String msg = makeString("LoadLibraryA failed with error code: "_s, GetLastError());
DWORD errorId = GetLastError();
LPWSTR messageBuffer = nullptr;
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
WTF::String msg = makeString("LoadLibrary failed: ", WTF::StringView((UCHAR*)messageBuffer, size));
LocalFree(messageBuffer);
#else
WTF::String msg = WTF::String::fromUTF8(dlerror());
#endif
Expand Down
25 changes: 25 additions & 0 deletions src/bun.js/bindings/exports.zig
Original file line number Diff line number Diff line change
Expand Up @@ -924,5 +924,30 @@ comptime {

TestScope.shim.ref();
BodyValueBuffererContext.shim.ref();

_ = Bun__LoadLibraryBunString;
}
}

/// Returns null on error. Use windows API to lookup the actual error.
/// The reason this function is in zig is so that we can use our own utf16-conversion functions.
///
/// Using characters16() does not seem to always have the sentinel. or something else
/// broke when I just used it. Not sure. ... but this works!
pub export fn Bun__LoadLibraryBunString(str: *bun.String) ?*anyopaque {
var buf: bun.WPathBuffer = undefined;
const data = switch (str.encoding()) {
.utf8 => bun.strings.convertUTF8toUTF16InBuffer(&buf, str.utf8()),
.utf16 => brk: {
@memcpy(buf[0..str.length()], str.utf16());
break :brk buf[0..str.length()];
},
.latin1 => brk: {
bun.strings.copyU8IntoU16(&buf, str.latin1());
break :brk buf[0..str.length()];
},
};
buf[data.len] = 0;
const LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;
return bun.windows.LoadLibraryExW(buf[0..data.len :0].ptr, null, LOAD_WITH_ALTERED_SEARCH_PATH);
}
10 changes: 7 additions & 3 deletions src/bun.js/javascript.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1709,15 +1709,19 @@ pub const VirtualMachine = struct {
const buster_name = name: {
if (std.fs.path.isAbsolute(normalized_specifier)) {
if (std.fs.path.dirname(normalized_specifier)) |dir| {
// With trailing slash
break :name if (dir.len == 1) dir else normalized_specifier[0 .. dir.len + 1];
// Normalized with trailing slash
break :name bun.strings.normalizeSlashesOnly(
&specifier_cache_resolver_buf,
if (dir.len == 1) dir else normalized_specifier[0 .. dir.len + 1],
'/',
);
}
}

var parts = [_]string{
source_to_use,
normalized_specifier,
"../",
bun.pathLiteral("../"),
};

break :name bun.path.joinAbsStringBufZTrailingSlash(
Expand Down
10 changes: 7 additions & 3 deletions src/bundler.zig
Original file line number Diff line number Diff line change
Expand Up @@ -402,14 +402,18 @@ pub const Bundler = struct {
const buster_name = name: {
if (std.fs.path.isAbsolute(entry_point)) {
if (std.fs.path.dirname(entry_point)) |dir| {
// With trailing slash
break :name if (dir.len == 1) dir else entry_point[0 .. dir.len + 1];
// Normalized with trailing slash
break :name bun.strings.normalizeSlashesOnly(
&cache_bust_buf,
if (dir.len == 1) dir else entry_point[0 .. dir.len + 1],
'/',
);
}
}

var parts = [_]string{
entry_point,
"../",
bun.pathLiteral("../"),
};

break :name bun.path.joinAbsStringBufZTrailingSlash(
Expand Down
3 changes: 3 additions & 0 deletions src/js/builtins/ReadableByteStreamInternals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ export function readableByteStreamControllerPull(controller) {
}

export function readableByteStreamControllerShouldCallPull(controller) {
$assert(controller);
const stream = $getByIdDirectPrivate(controller, "controlledReadableStream");
$assert(stream);

if ($getByIdDirectPrivate(stream, "state") !== $streamReadable) return false;
if ($getByIdDirectPrivate(controller, "closeRequested")) return false;
Expand All @@ -244,6 +246,7 @@ export function readableByteStreamControllerShouldCallPull(controller) {
}

export function readableByteStreamControllerCallPullIfNeeded(controller) {
$assert(controller);
if (!$readableByteStreamControllerShouldCallPull(controller)) return;

if ($getByIdDirectPrivate(controller, "pulling")) {
Expand Down
2 changes: 1 addition & 1 deletion src/string.zig
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ pub const String = extern struct {
return "";
}

pub fn encoding(self: String) bun.strings.Encoding {
pub fn encoding(self: String) bun.strings.EncodingNonAscii {
if (self.isUTF16()) {
return .utf16;
}
Expand Down
35 changes: 25 additions & 10 deletions src/string_immutable.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ pub const Encoding = enum {
utf16,
};

/// Returned by classification functions that do not discriminate between utf8 and ascii.
pub const EncodingNonAscii = enum {
utf8,
utf16,
latin1,
};

pub inline fn containsChar(self: string, char: u8) bool {
return indexOfChar(self, char) != null;
}
Expand Down Expand Up @@ -1774,17 +1781,8 @@ pub fn toWPathNormalizeAutoExtend(wbuf: []u16, utf8: []const u8) [:0]const u16 {

pub fn toWPathNormalized(wbuf: []u16, utf8: []const u8) [:0]const u16 {
var renormalized: [bun.MAX_PATH_BYTES]u8 = undefined;
var path_to_use = utf8;

if (bun.strings.containsChar(utf8, '/')) {
@memcpy(renormalized[0..utf8.len], utf8);
for (renormalized[0..utf8.len]) |*c| {
if (c.* == '/') {
c.* = '\\';
}
}
path_to_use = renormalized[0..utf8.len];
}
var path_to_use = normalizeSlashesOnly(&renormalized, utf8, '\\');

// is there a trailing slash? Let's remove it before converting to UTF-16
if (path_to_use.len > 3 and bun.path.isSepAny(path_to_use[path_to_use.len - 1])) {
Expand All @@ -1794,6 +1792,23 @@ pub fn toWPathNormalized(wbuf: []u16, utf8: []const u8) [:0]const u16 {
return toWPath(wbuf, path_to_use);
}

pub fn normalizeSlashesOnly(buf: []u8, utf8: []const u8, comptime desired_slash: u8) []const u8 {
comptime std.debug.assert(desired_slash == '/' or desired_slash == '\\');
const undesired_slash = if (desired_slash == '/') '\\' else '/';

if (bun.strings.containsChar(utf8, undesired_slash)) {
@memcpy(buf[0..utf8.len], utf8);
for (buf[0..utf8.len]) |*c| {
if (c.* == undesired_slash) {
c.* = desired_slash;
}
}
return buf[0..utf8.len];
}

return utf8;
}

pub fn toWDirNormalized(wbuf: []u16, utf8: []const u8) [:0]const u16 {
var renormalized: [bun.MAX_PATH_BYTES]u8 = undefined;
var path_to_use = utf8;
Expand Down
2 changes: 2 additions & 0 deletions src/windows.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2985,6 +2985,8 @@ pub extern fn LoadLibraryA(
[*:0]const u8,
) ?*anyopaque;

pub extern fn LoadLibraryExW([*:0]const u16, ?HANDLE, DWORD) ?*anyopaque;

pub extern "kernel32" fn CreateHardLinkW(
newFileName: LPCWSTR,
existingFileName: LPCWSTR,
Expand Down
7 changes: 1 addition & 6 deletions test/cli/hot/hot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,9 @@ it("should not hot reload when a random file is written", async () => {
writeFileSync(root + ".another.yet.js", code);
unlinkSync(root + ".another.yet.js");
}
var waiter = new Promise<void>((resolve, reject) => {
setTimeout(async () => {
resolve();
}, 50);
});
var finished = false;
await Promise.race([
waiter,
Bun.sleep(200),
(async () => {
if (finished) {
return;
Expand Down
25 changes: 15 additions & 10 deletions test/cli/run/require-cache.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect, describe } from "bun:test";
import { bunEnv, bunExe } from "harness";
import { bunEnv, bunExe, isWindows } from "harness";
import { join } from "path";

// This also tests __dirname and __filename
Expand Down Expand Up @@ -63,14 +63,19 @@ describe("files transpiled and loaded don't leak file paths", () => {
expect(exitCode).toBe(0);
}, 30000);

test("via import()", () => {
const { stdout, exitCode } = Bun.spawnSync({
cmd: [bunExe(), "--smol", "run", join(import.meta.dir, "esm-fixture-leak-small.mjs")],
env: bunEnv,
stderr: "inherit",
});
test(
"via import()",
() => {
const { stdout, exitCode } = Bun.spawnSync({
cmd: [bunExe(), "--smol", "run", join(import.meta.dir, "esm-fixture-leak-small.mjs")],
env: bunEnv,
stderr: "inherit",
});

expect(stdout.toString().trim()).toEndWith("--pass--");
expect(exitCode).toBe(0);
}, 30000);
expect(stdout.toString().trim()).toEndWith("--pass--");
expect(exitCode).toBe(0);
},
// TODO: Investigate why this is so slow on Windows
isWindows ? 60000 : 30000,
);
});

0 comments on commit 0994132

Please sign in to comment.