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
48 changes: 46 additions & 2 deletions build/gulpfile.reh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,48 @@ function extractAlpinefromDocker(nodeVersion: string, platform: string, arch: st
return es.readArray([new File({ path: 'node', contents, stat: { mode: parseInt('755', 8) } as fs.Stats })]);
}

// WSL1 binfmt_elf rejects PT_LOAD segments with p_align > PAGE_SIZE (0x1000).
// Node 24 linux-x64 ships an `lpstub` LOAD segment aligned to 2 MiB for hugepage
// remapping; clamp it so the binary still loads under WSL1.
function patchElfLoadAlign(): NodeJS.ReadWriteStream {
return es.mapSync<File, File>(file => {
if (!file.contents || !Buffer.isBuffer(file.contents)) {
return file;
}
const buf = file.contents;
if (buf.length < 64) {
return file;
}
if (buf[0] !== 0x7f || buf[1] !== 0x45 || buf[2] !== 0x4c || buf[3] !== 0x46) {
return file;
}
if (buf[4] !== 2 /* ELFCLASS64 */ || buf[5] !== 1 /* ELFDATA2LSB */) {
return file;
}
const e_phoff = Number(buf.readBigUInt64LE(0x20));
const e_phentsize = buf.readUInt16LE(0x36);
const e_phnum = buf.readUInt16LE(0x38);
if (e_phentsize !== 56) {
return file;
}
Comment thread
deepak1556 marked this conversation as resolved.
const PT_LOAD = 1;
const MAX_ALIGN = 0x1000n;
for (let i = 0; i < e_phnum; i++) {
const off = e_phoff + i * e_phentsize;
if (off + e_phentsize > buf.length) {
break;
}
if (buf.readUInt32LE(off) !== PT_LOAD) {
continue;
}
if (buf.readBigUInt64LE(off + 48) > MAX_ALIGN) {
buf.writeBigUInt64LE(MAX_ALIGN, off + 48);
}
}
return file;
});
}

const { nodeVersion, internalNodeVersion } = getNodeVersion();

BUILD_TARGETS.forEach(({ platform, arch }) => {
Expand Down Expand Up @@ -229,14 +271,16 @@ function nodejs(platform: string, arch: string): NodeJS.ReadWriteStream | undefi
fetchUrls(`/dist/v${nodeVersion}/win-${arch}/node.exe`, { base: 'https://nodejs.org', checksumSha256 }))
.pipe(rename('node.exe'));
case 'darwin':
case 'linux':
return (product.nodejsRepository !== 'https://nodejs.org' ?
case 'linux': {
const downloaded = (product.nodejsRepository !== 'https://nodejs.org' ?
fetchGithub(product.nodejsRepository, { version: `${nodeVersion}-${internalNodeVersion}`, name: expectedName!, checksumSha256 }) :
fetchUrls(`/dist/v${nodeVersion}/node-v${nodeVersion}-${platform}-${arch}.tar.gz`, { base: 'https://nodejs.org', checksumSha256 })
).pipe(flatmap(stream => stream.pipe(gunzip()).pipe(untar())))
.pipe(filter('**/node'))
.pipe(util.setExecutableBit('**'))
.pipe(rename('node'));
return platform === 'linux' && arch === 'x64' ? downloaded.pipe(patchElfLoadAlign()) : downloaded;
}
case 'alpine':
return product.nodejsRepository !== 'https://nodejs.org' ?
fetchGithub(product.nodejsRepository, { version: `${nodeVersion}-${internalNodeVersion}`, name: expectedName!, checksumSha256 })
Expand Down
33 changes: 0 additions & 33 deletions test/sanity/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export class TestContext {

private readonly tempDirs = new Set<string>();
private readonly wslTempDirs = new Set<string>();
private readonly patchedWslNodePaths = new Set<string>();
private nextPort = 3010;
private currentTestName: string | undefined;
private screenshotCounter = 0;
Expand Down Expand Up @@ -257,38 +256,6 @@ export class TestContext {
return undefined;
}

/**
* On WSL1, patches the Node.js binary used by the server to remove ELF note sections
* that cause Node 24 to fail to start. No-op on WSL2.
* @param wslEntryPoint The WSL path to the server entry point script.
*/
public applyWsl1Node24Workaround(wslEntryPoint: string): void {
if (this.getUbuntuWslVersion() !== 1) {
return;
}

const wslNodePath = wslEntryPoint.replace(/\/bin\/[^/]+$/, '/node');
if (this.patchedWslNodePaths.has(wslNodePath)) {
return;
}

this.patchedWslNodePaths.add(wslNodePath);
this.warn(`Applying WSL1 Node 24 workaround for ${wslNodePath}`);

const shellScript = [
'set -e',
`node_path='${wslNodePath}'`,
'backup_path="${node_path}.orig"',
'if [ -f "${backup_path}" ]; then exit 0; fi',
'if ! command -v objcopy >/dev/null 2>&1; then apt-get update && apt-get install -y binutils; fi',
'cp "${node_path}" "${backup_path}"',
'objcopy --remove-section .note.ABI-tag --remove-section .note.gnu.build-id --remove-section .note.gnu.property "${backup_path}" "${node_path}"',
'chmod +x "${node_path}"',
].join('; ');

this.runNoErrors('wsl', '-d', 'Ubuntu', 'sh', '-lc', shellScript);
}

/**
* Ensures that the directory for the specified file path exists.
*/
Expand Down
2 changes: 0 additions & 2 deletions test/sanity/src/wsl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ export function setup(context: TestContext) {
}

const wslEntryPoint = context.toWslPath(entryPoint);
context.applyWsl1Node24Workaround(wslEntryPoint);

await context.runCliApp('WSL Server', 'wsl',
[
Expand Down Expand Up @@ -102,7 +101,6 @@ export function setup(context: TestContext) {
const test = new WslUITest(context, undefined, wslWorkspaceDir, wslExtensionsDir);

const wslEntryPoint = context.toWslPath(entryPoint);
context.applyWsl1Node24Workaround(wslEntryPoint);

await context.runCliApp('WSL Server', 'wsl',
[
Expand Down
Loading