Skip to content

Commit

Permalink
fix(engine-core): use RTLD_DEEPBIND flag when loading the addon (#18426)
Browse files Browse the repository at this point in the history
Fixes: #10649
Fixes: #17946
Fixes: #16897
Fixes: #17223
Fixes: #18336
Fixes: #18559
  • Loading branch information
aqrln committed Apr 14, 2023
1 parent d452662 commit 8d87367
Showing 1 changed file with 51 additions and 3 deletions.
54 changes: 51 additions & 3 deletions packages/engine-core/src/library/DefaultLibraryLoader.ts
Expand Up @@ -4,6 +4,7 @@ import type { Platform } from '@prisma/get-platform'
import { getNodeAPIName, getPlatform, getPlatformWithOSResult } from '@prisma/get-platform'
import chalk from 'chalk'
import fs from 'fs'
import os from 'os'
import path from 'path'

import { EngineConfig } from '../common/Engine'
Expand All @@ -16,9 +17,56 @@ import { Library, LibraryLoader } from './types/Library'

const debug = Debug('prisma:client:libraryEngine:loader')

export function load<T>(id: string): T {
// this require needs to be resolved at runtime, tell webpack to ignore it
return eval('require')(id) as T
const libraryCacheSymbol = Symbol('PrismaLibraryEngineCache')

type LibraryCache = Record<string, Library | undefined>

type GlobalWithCache = typeof globalThis & {
[libraryCacheSymbol]?: LibraryCache
}

function getLibraryCache(): LibraryCache {
const globalWithCache = globalThis as GlobalWithCache
if (globalWithCache[libraryCacheSymbol] === undefined) {
globalWithCache[libraryCacheSymbol] = {}
}
return globalWithCache[libraryCacheSymbol]
}

export function load(libraryPath: string): Library {
const cache = getLibraryCache()

if (cache[libraryPath] !== undefined) {
return cache[libraryPath]!
}

// `toNamespacedPath` is required for native addons on Windows, but it's a no-op on other systems.
// We call it here unconditionally just like `.node` CommonJS loader in Node.js does.
const fullLibraryPath = path.toNamespacedPath(libraryPath)
const libraryModule = { exports: {} as Library }

let flags = 0

if (process.platform !== 'win32') {
// Add RTLD_LAZY and RTLD_DEEPBIND on Unix.
//
// RTLD_LAZY: this is what Node.js uses by default on all Unix-like systems
// if no flags were passed to dlopen from JavaScript side.
//
// RTLD_DEEPBIND: this is not a part of POSIX standard but a widely
// supported extension. It prevents issues when we dynamically link to
// system OpenSSL on Linux but the dynamic linker resolves the symbols from
// the Node.js binary instead.
//
// @ts-expect-error TODO: typings don't define dlopen -- needs to be fixed upstream
flags = os.constants.dlopen.RTLD_LAZY | os.constants.dlopen.RTLD_DEEPBIND
}

// @ts-expect-error TODO: typings don't define dlopen -- needs to be fixed upstream
process.dlopen(libraryModule, fullLibraryPath, flags)

cache[libraryPath] = libraryModule.exports
return libraryModule.exports
}

export class DefaultLibraryLoader implements LibraryLoader {
Expand Down

0 comments on commit 8d87367

Please sign in to comment.