-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add process.dlopenFlags #12794
Add process.dlopenFlags #12794
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ | |
// Deprecation Code: DEP0008 | ||
const constants = process.binding('constants'); | ||
Object.assign(exports, | ||
constants.os.dlopen, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should add things to something that's already deprecated. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has already been discussed, on this same PR-thread. I'll let you do the digging. (BTW: this is where mailing lists outpass github PRs: it's so much harder to dig discussion history). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, in that case SGTM. Sorry about not reading through the entire thread – though in my defense it is quite long. |
||
constants.os.errno, | ||
constants.os.signals, | ||
constants.fs, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,6 +117,10 @@ typedef int mode_t; | |
#include <grp.h> // getgrnam() | ||
#endif | ||
|
||
#if defined(__POSIX__) | ||
#include <dlfcn.h> | ||
#endif | ||
|
||
#ifdef __APPLE__ | ||
#include <crt_externs.h> | ||
#define environ (*_NSGetEnviron()) | ||
|
@@ -2503,36 +2507,85 @@ struct node_module* get_linked_module(const char* name) { | |
return mp; | ||
} | ||
|
||
// DLOpen is process.dlopen(module, filename). | ||
struct DLib { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Already discussed. See above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I couldn't find the actual discussion corresponding to this. I know it is exhausting to search through it, but if you could find it, please point me to it. I'll try again when I get back home. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On #12794 (comment) it was suggested to do a class. So I did it and commented There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I didn't check properly then. |
||
std::string filename_; | ||
std::string errmsg_; | ||
void* handle_; | ||
int flags_; | ||
|
||
#ifdef __POSIX__ | ||
static const int kDefaultFlags = RTLD_LAZY; | ||
|
||
bool Open() { | ||
handle_ = dlopen(filename_.c_str(), flags_); | ||
if (handle_ != nullptr) | ||
return true; | ||
errmsg_ = dlerror(); | ||
return false; | ||
} | ||
|
||
void Close() { | ||
if (handle_ != nullptr) | ||
dlclose(handle_); | ||
} | ||
#else // !__POSIX__ | ||
static const int kDefaultFlags = 0; | ||
uv_lib_t lib_; | ||
|
||
bool Open() { | ||
int ret = uv_dlopen(filename_.c_str(), &lib_); | ||
if (ret == 0) { | ||
handle_ = static_cast<void*>(lib_.handle); | ||
return true; | ||
} | ||
errmsg_ = uv_dlerror(&lib_); | ||
uv_dlclose(&lib_); | ||
return false; | ||
} | ||
|
||
void Close() { | ||
uv_dlclose(&lib_); | ||
} | ||
#endif // !__POSIX__ | ||
}; | ||
|
||
// DLOpen is process.dlopen(module, filename, flags). | ||
// Used to load 'module.node' dynamically shared objects. | ||
// | ||
// FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict | ||
// when two contexts try to load the same shared object. Maybe have a shadow | ||
// cache that's a plain C list or hash table that's shared across contexts? | ||
static void DLOpen(const FunctionCallbackInfo<Value>& args) { | ||
Environment* env = Environment::GetCurrent(args); | ||
uv_lib_t lib; | ||
|
||
CHECK_EQ(modpending, nullptr); | ||
|
||
if (args.Length() != 2) { | ||
env->ThrowError("process.dlopen takes exactly 2 arguments."); | ||
if (args.Length() < 2) { | ||
env->ThrowError("process.dlopen needs at least 2 arguments."); | ||
return; | ||
} | ||
|
||
int32_t flags = DLib::kDefaultFlags; | ||
if (args.Length() > 2 && !args[2]->Int32Value(env->context()).To(&flags)) { | ||
return env->ThrowTypeError("flag argument must be an integer."); | ||
} | ||
|
||
Local<Object> module = args[0]->ToObject(env->isolate()); // Cast | ||
node::Utf8Value filename(env->isolate(), args[1]); // Cast | ||
const bool is_dlopen_error = uv_dlopen(*filename, &lib); | ||
DLib dlib; | ||
dlib.filename_ = *filename; | ||
dlib.flags_ = flags; | ||
bool is_opened = dlib.Open(); | ||
|
||
// Objects containing v14 or later modules will have registered themselves | ||
// on the pending list. Activate all of them now. At present, only one | ||
// module per object is supported. | ||
node_module* const mp = modpending; | ||
modpending = nullptr; | ||
|
||
if (is_dlopen_error) { | ||
Local<String> errmsg = OneByteString(env->isolate(), uv_dlerror(&lib)); | ||
uv_dlclose(&lib); | ||
if (!is_opened) { | ||
Local<String> errmsg = OneByteString(env->isolate(), dlib.errmsg_.c_str()); | ||
dlib.Close(); | ||
#ifdef _WIN32 | ||
// Windows needs to add the filename into the error message | ||
errmsg = String::Concat(errmsg, args[1]->ToString(env->isolate())); | ||
|
@@ -2542,7 +2595,7 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) { | |
} | ||
|
||
if (mp == nullptr) { | ||
uv_dlclose(&lib); | ||
dlib.Close(); | ||
env->ThrowError("Module did not self-register."); | ||
return; | ||
} | ||
|
@@ -2569,18 +2622,18 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) { | |
} | ||
|
||
// NOTE: `mp` is allocated inside of the shared library's memory, calling | ||
// `uv_dlclose` will deallocate it | ||
uv_dlclose(&lib); | ||
// `dlclose` will deallocate it | ||
dlib.Close(); | ||
env->ThrowError(errmsg); | ||
return; | ||
} | ||
if (mp->nm_flags & NM_F_BUILTIN) { | ||
uv_dlclose(&lib); | ||
dlib.Close(); | ||
env->ThrowError("Built-in module self-registered."); | ||
return; | ||
} | ||
|
||
mp->nm_dso_handle = lib.handle; | ||
mp->nm_dso_handle = dlib.handle_; | ||
mp->nm_link = modlist_addon; | ||
modlist_addon = mp; | ||
|
||
|
@@ -2592,7 +2645,7 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) { | |
} else if (mp->nm_register_func != nullptr) { | ||
mp->nm_register_func(exports, module, mp->nm_priv); | ||
} else { | ||
uv_dlclose(&lib); | ||
dlib.Close(); | ||
env->ThrowError("Module has no declared entry point."); | ||
return; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#include <node.h> | ||
#include <v8.h> | ||
|
||
#ifndef _WIN32 | ||
|
||
#include <dlfcn.h> | ||
|
||
extern "C" const char* dlopen_pong(void) { | ||
return "pong"; | ||
} | ||
|
||
namespace { | ||
|
||
using v8::FunctionCallbackInfo; | ||
using v8::Isolate; | ||
using v8::Local; | ||
using v8::Object; | ||
using v8::String; | ||
using v8::Value; | ||
|
||
typedef const char* (*ping)(void); | ||
|
||
static ping ping_func; | ||
|
||
void LoadLibrary(const FunctionCallbackInfo<Value>& args) { | ||
const String::Utf8Value filename(args[0]); | ||
void* handle = dlopen(*filename, RTLD_LAZY); | ||
assert(handle != nullptr); | ||
ping_func = reinterpret_cast<ping>(dlsym(handle, "dlopen_ping")); | ||
assert(ping_func != nullptr); | ||
} | ||
|
||
void Ping(const FunctionCallbackInfo<Value>& args) { | ||
Isolate* isolate = args.GetIsolate(); | ||
assert(ping_func != nullptr); | ||
args.GetReturnValue().Set(String::NewFromUtf8(isolate, ping_func())); | ||
} | ||
|
||
void init(Local<Object> exports) { | ||
NODE_SET_METHOD(exports, "load", LoadLibrary); | ||
NODE_SET_METHOD(exports, "ping", Ping); | ||
} | ||
|
||
NODE_MODULE(binding, init) | ||
|
||
} // anonymous namespace | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suspect that you need to wrap this whole file in a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
|
||
#endif // _WIN32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Care to link http://man7.org/linux/man-pages/man3/dlopen.3.html?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it done automagically? I think we already discussed this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad. Yes, tools/doc/html.js will take care of this.