windows: random things (#9046)

* random things

* fix reliability of loading napi stuff

* fix posix build

* a
This commit is contained in:
dave caruso
2024-02-27 16:30:34 -08:00
committed by GitHub
parent c9b5191fc2
commit c54844b30b
11 changed files with 97 additions and 38 deletions

View File

@@ -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,

View File

@@ -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))
{
@@ -291,8 +293,8 @@ 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);
@@ -300,7 +302,12 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen,
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

View File

@@ -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);
}

View File

@@ -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(

View File

@@ -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(

View File

@@ -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;
@@ -244,6 +246,7 @@ export function readableByteStreamControllerShouldCallPull(controller) {
}
export function readableByteStreamControllerCallPullIfNeeded(controller) {
$assert(controller);
if (!$readableByteStreamControllerShouldCallPull(controller)) return;
if ($getByIdDirectPrivate(controller, "pulling")) {

View File

@@ -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;
}

View File

@@ -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;
}
@@ -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])) {
@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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
@@ -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,
);
});