Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
unix, win: rework uv_dlopen() API
Browse files Browse the repository at this point in the history
  • Loading branch information
bnoordhuis committed May 3, 2012
1 parent 93d16e6 commit 5d19aa8
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 96 deletions.
5 changes: 4 additions & 1 deletion include/uv-private/uv-unix.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ typedef gid_t uv_gid_t;
typedef uid_t uv_uid_t; typedef uid_t uv_uid_t;


/* Platform-specific definitions for uv_dlopen support. */ /* Platform-specific definitions for uv_dlopen support. */
typedef void* uv_lib_t;
#define UV_DYNAMIC /* empty */ #define UV_DYNAMIC /* empty */
typedef struct {
void* handle;
char* errmsg;
} uv_lib_t;


#define UV_HANDLE_TYPE_PRIVATE /* empty */ #define UV_HANDLE_TYPE_PRIVATE /* empty */
#define UV_REQ_TYPE_PRIVATE /* empty */ #define UV_REQ_TYPE_PRIVATE /* empty */
Expand Down
5 changes: 4 additions & 1 deletion include/uv-private/uv-win.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -192,8 +192,11 @@ typedef unsigned char uv_uid_t;
typedef unsigned char uv_gid_t; typedef unsigned char uv_gid_t;


/* Platform-specific definitions for uv_dlopen support. */ /* Platform-specific definitions for uv_dlopen support. */
typedef HMODULE uv_lib_t;
#define UV_DYNAMIC FAR WINAPI #define UV_DYNAMIC FAR WINAPI
typedef struct {
HMODULE handle;
char* errmsg;
} uv_lib_t;


RB_HEAD(uv_timer_tree_s, uv_timer_s); RB_HEAD(uv_timer_tree_s, uv_timer_s);


Expand Down
21 changes: 12 additions & 9 deletions include/uv.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1532,23 +1532,26 @@ UV_EXTERN extern uint64_t uv_hrtime(void);




/* /*
* Opens a shared library. The filename is in utf-8. On success, -1 is returned * Opens a shared library. The filename is in utf-8. Returns 0 on success and
* and the variable pointed by library receives a handle to the library. * -1 on error. Call `uv_dlerror(uv_lib_t*)` to get the error message.
*/ */
UV_EXTERN uv_err_t uv_dlopen(const char* filename, uv_lib_t* library); UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib);
UV_EXTERN uv_err_t uv_dlclose(uv_lib_t library);
/*
* Close the shared libary.
*/
UV_EXTERN void uv_dlclose(uv_lib_t* lib);


/* /*
* Retrieves a data pointer from a dynamic library. It is legal for a symbol to * Retrieves a data pointer from a dynamic library. It is legal for a symbol to
* map to NULL. * map to NULL. Returns 0 on success and -1 if the symbol was not found.
*/ */
UV_EXTERN uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr); UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);


/* /*
* Retrieves and frees an error message of dynamic linking loaders. * Returns the last uv_dlopen() or uv_dlsym() error message.
*/ */
UV_EXTERN const char *uv_dlerror(uv_lib_t library); UV_EXTERN const char* uv_dlerror(uv_lib_t* lib);
UV_EXTERN void uv_dlerror_free(uv_lib_t library, const char *msg);


/* /*
* The mutex functions return 0 on success, -1 on error * The mutex functions return 0 on success, -1 on error
Expand Down
78 changes: 37 additions & 41 deletions src/unix/dl.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -27,65 +27,61 @@
#include <string.h> #include <string.h>
#include <locale.h> #include <locale.h>


/* The dl family of functions don't set errno. We need a good way to communicate static int uv__dlerror(uv_lib_t* lib);
* errors to the caller but there is only dlerror() and that returns a string -
* a string that may or may not be safe to keep a reference to...
*/
static const uv_err_t uv_err_ = { UV_ENOENT, ENOENT };



uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) {
void* handle = dlopen(filename, RTLD_LAZY);
if (handle == NULL) {
return uv_err_;
}


*library = handle; int uv_dlopen(const char* filename, uv_lib_t* lib) {
return uv_ok_; lib->errmsg = NULL;
lib->handle = dlopen(filename, RTLD_LAZY);
return uv__dlerror(lib);
} }




uv_err_t uv_dlclose(uv_lib_t library) { void uv_dlclose(uv_lib_t* lib) {
if (dlclose(library) != 0) { if (lib->errmsg) {
return uv_err_; free(lib->errmsg);
lib->errmsg = NULL;
} }


return uv_ok_; if (lib->handle) {
/* Ignore errors. No good way to signal them without leaking memory. */
dlclose(lib->handle);
lib->handle = NULL;
}
} }




uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr) { int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
void* address; dlerror(); /* Reset error status. */

*ptr = dlsym(lib->handle, name);
/* Reset error status. */ return uv__dlerror(lib);
dlerror(); }

address = dlsym(library, name);


if (dlerror()) {
return uv_err_;
}


*ptr = (void*) address; const char* uv_dlerror(uv_lib_t* lib) {
return uv_ok_; return lib->errmsg ? lib->errmsg : "no error";
} }




const char *uv_dlerror(uv_lib_t library) { static int uv__dlerror(uv_lib_t* lib) {
const char* buf = NULL; char* errmsg;
/* Make uv_dlerror() be independent of locale */ char* locale;
char* loc = setlocale(LC_MESSAGES, NULL);
if(strcmp(loc, "C") == 0) { /* Make error message independent of locale. */
return strdup(dlerror()); locale = setlocale(LC_MESSAGES, NULL);
if (strcmp(locale, "C") == 0) {
errmsg = dlerror();
} else { } else {
setlocale(LC_MESSAGES, "C"); setlocale(LC_MESSAGES, "C");
buf = dlerror(); errmsg = dlerror();
setlocale(LC_MESSAGES, loc); setlocale(LC_MESSAGES, locale);
return strdup(buf);
} }
}


if (lib->errmsg)
free(lib->errmsg);


void uv_dlerror_free(uv_lib_t library, const char *msg) { if (errmsg)
free((void*)msg); return lib->errmsg = strdup(errmsg), -1;
else
return lib->errmsg = NULL, 0;
} }
76 changes: 40 additions & 36 deletions src/win/dl.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,61 +22,65 @@
#include "uv.h" #include "uv.h"
#include "internal.h" #include "internal.h"


__declspec( thread ) DWORD saved_errno = 0; static int uv__dlerror(uv_lib_t* lib, int errorno);


uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) {
int uv_dlopen(const char* filename, uv_lib_t* lib) {
wchar_t filename_w[32768]; wchar_t filename_w[32768];
HMODULE handle;


if (!uv_utf8_to_utf16(filename, lib->handle = NULL;
filename_w, lib->errmsg = NULL;
sizeof(filename_w) / sizeof(wchar_t))) {
saved_errno = GetLastError(); if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) {
return uv__new_sys_error(saved_errno); return uv__dlerror(lib, GetLastError());
} }


handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (handle == NULL) { if (lib->handle == NULL) {
saved_errno = GetLastError(); return uv__dlerror(lib, GetLastError());
return uv__new_sys_error(saved_errno);
} }


*library = handle; return 0;
return uv_ok_;
} }




uv_err_t uv_dlclose(uv_lib_t library) { void uv_dlclose(uv_lib_t* lib) {
if (!FreeLibrary(library)) { if (lib->errmsg) {
saved_errno = GetLastError(); LocalFree((void*)lib->errmsg);
return uv__new_sys_error(saved_errno); lib->errmsg = NULL;
} }


return uv_ok_; if (lib->handle) {
/* Ignore errors. No good way to signal them without leaking memory. */
FreeLibrary(lib->handle);
lib->handle = NULL;
}
} }




uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr) { int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
FARPROC proc = GetProcAddress(library, name); *ptr = (void*) GetProcAddress(lib->handle, name);
if (proc == NULL) { return uv__dlerror(lib, *ptr ? 0 : GetLastError());
saved_errno = GetLastError();
return uv__new_sys_error(saved_errno);
}

*ptr = (void*) proc;
return uv_ok_;
} }




const char *uv_dlerror(uv_lib_t library) { const char* uv_dlerror(uv_lib_t* lib) {
char* buf = NULL; return lib->errmsg ? lib->errmsg : "no error";
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, saved_errno,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&buf, 0, NULL);
return buf;
} }




void uv_dlerror_free(uv_lib_t library, const char *msg) { static int uv__dlerror(uv_lib_t* lib, int errorno) {
LocalFree((LPVOID)msg); if (lib->errmsg) {
LocalFree((void*)lib->errmsg);
lib->errmsg = NULL;
}

if (errorno) {
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(LPSTR)&lib->errmsg, 0, NULL);
}

return errorno ? -1 : 0;
} }
25 changes: 17 additions & 8 deletions test/test-dlerror.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
#include "task.h" #include "task.h"
#include <string.h> #include <string.h>


const char* path = "test/fixtures/load_error.node";
const char* msg; TEST_IMPL(dlerror) {
const char* path = "test/fixtures/load_error.node";
const char* msg;
uv_lib_t lib;
int r;


#ifdef __linux__ #ifdef __linux__
const char* dlerror_desc = "file too short"; const char* dlerror_desc = "file too short";
Expand All @@ -36,14 +40,19 @@ const char* msg;
const char* dlerror_desc = ""; const char* dlerror_desc = "";
#endif #endif


uv_lib_t lib;
uv_err_t r;

TEST_IMPL(dlerror) {
r = uv_dlopen(path, &lib); r = uv_dlopen(path, &lib);
msg = uv_dlerror(lib); ASSERT(r == -1);

msg = uv_dlerror(&lib);
ASSERT(msg != NULL); ASSERT(msg != NULL);
ASSERT(strstr(msg, dlerror_desc) != NULL); ASSERT(strstr(msg, dlerror_desc) != NULL);
uv_dlerror_free(lib, msg);
/* Should return the same error twice in a row. */
msg = uv_dlerror(&lib);
ASSERT(msg != NULL);
ASSERT(strstr(msg, dlerror_desc) != NULL);

uv_dlclose(&lib);

return 0; return 0;
} }

7 comments on commit 5d19aa8

@txdv
Copy link
Contributor

@txdv txdv commented on 5d19aa8 May 5, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regression in error handling:
No way to check if the file was malformed or simply does not exist.

@bnoordhuis
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@txdv You're referring to the Windows implementation? That's feature parity with UNIX because it never was possible on UNIX in the first place.

@piscisaureus
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah we are being crippled by the dumbass os again.

@piscisaureus
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw does dlerror() not report it?

@bnoordhuis
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only as a string, it doesn't set errno.

@piscisaureus
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

laaaaaaaaaaaaaame

Edit: it's saturday.

@bnoordhuis
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah, I figured it was something like that. Please step back from that keyboard, Mr. Belder.

Please sign in to comment.