Skip to content
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

Replace dlfcn-win32 with simple-dlfcn-win32 #226

Closed
wants to merge 8 commits into from

Conversation

mcnameej
Copy link
Contributor

@mcnameej mcnameej commented Aug 7, 2015

I'm submitting two PR's to fix #223. Pick one. This PR replaces the dlfcn-win32 code.

@unbornchikken
Copy link
Member

I'd go with this definitely, but in this case, we don't need this to reside in deps. Could you integrate it with src?

Thanks a lot!

(2) Convert filename from UTF-8 to UCS-2 and use LibraryLibraryW().
(3) Code clean up and hardening.
@mcnameej
Copy link
Contributor Author

mcnameej commented Aug 8, 2015

Three test cases fail with my version of dlfcn...

1) Library should accept `null` as a first argument:
   Error: Dynamic Symbol Retrieval Error: Win32 error 127
    at DynamicLibrary.get (C:\Proj\iojs\node-ffi\lib\dynamic_library.js:112:11)
    at C:\Proj\iojs\node-ffi\lib\library.js:50:19
    at Array.forEach (native)
    at new Library (C:\Proj\iojs\node-ffi\lib\library.js:47:28)
    at Context.<anonymous> (C:\Proj\iojs\node-ffi\test\library.js:24:21)

2) Library should work with "strcpy" and a 128 length string:
   Error: Dynamic Symbol Retrieval Error: Win32 error 127
    at DynamicLibrary.get (C:\Proj\iojs\node-ffi\lib\dynamic_library.js:112:11)
    at C:\Proj\iojs\node-ffi\lib\library.js:50:19
    at Array.forEach (native)
    at new Library (C:\Proj\iojs\node-ffi\lib\library.js:47:28)
    at Context.<anonymous> (C:\Proj\iojs\node-ffi\test\library.js:64:18)

3) Library should work with "strcpy" and a 2k length string:
   Error: Dynamic Symbol Retrieval Error: Win32 error 127
    at DynamicLibrary.get (C:\Proj\iojs\node-ffi\lib\dynamic_library.js:112:11)
    at C:\Proj\iojs\node-ffi\lib\library.js:50:19
    at Array.forEach (native)
    at new Library (C:\Proj\iojs\node-ffi\lib\library.js:47:28)
    at Context.<anonymous> (C:\Proj\iojs\node-ffi\test\library.js:74:18)

These test cases depend on POSIX semantics in dlsym: searching all loaded modules to find a symbol by name. No Windows programmer would ever think to do that.

When you search for "strcpy", which strcpy() do you expect to find? ntdll.dll is loaded into all processes, and it exports strcpy. msvcrt.dll is loaded into most processes, but it belongs to the OS -- node.exe doesn't use it. In fact, node.exe static links it's C runtime, and those symbols are unavailable (even the original dlfcn-win32, which tries to emulate POSIX, can't see them). If node.exe did use a C runtime DLL, it would be something like msvcr120.dll. You have several DLL's loaded in your process that export "strcpy". Which one will dlsym return? Who knows.

It probably doesn't matter which runtime you get strcpy() from. It matters a lot for things like malloc(), free(), fopen(), and fclose(). Memory allocated by malloc() must be passed to the free() in the same C runtime as the malloc() that allocated it. The FILE* returned by fopen() can only be passed to stdio functions in the same C runtime. This is why Windows DLL's generally don't use stdio FILE's in their public interface, and if they have functions that return an allocated buffer, they'll provide a function to free it (or they'll allocate the memory using a Win32 API like GlobalAlloc() or HeapAlloc(), which any caller can free).

@unbornchikken
Copy link
Member

I understand your point, and agree. I think those test are not there to test strcmp, those are there to test if binding is works or not by the given situation. If you could replace them with an invocations of an strcmp wrapper method in ffi_test.node, then I'd accept it that way. That node file is just a dynamic lib, so it gotta work that way. @TooTallNate waddaya say?

(1) Avoid depending on POSIX dynamic library semantics.
(2) Check handling of Unicode characters in path/filename.
@mcnameej
Copy link
Contributor Author

mcnameej commented Aug 8, 2015

P.S. My last commit included a Unicode test case similar to PR #225.

@unbornchikken
Copy link
Member

So to sum it up:

  • finally we can drop another dependency, only ffi remains
  • we have a simplifed dlopen and co. on Windows that also fixes Dll pathname with non-ascii characters #183
  • there are some updated test cases of testing the same node-ffi behavior, but wouldn't encourage anyone to use node-ffi in a way that never really works right on Windows

@TooTallNate that's what I call pull request. Could be merged ASAP. Agree?

@unbornchikken
Copy link
Member

I celebrated too early. Unfortunattely we have some failing test cases by merging this on Linux. Please take a look at the Travis log. Do you have experience to fix them? If not, I can help you with this.

@mcnameej
Copy link
Contributor Author

I'll fire up a Linux VM and investigate the failures reported by travis.

Not sure what to make of the failures reported by AppVeyor. Is that a problem with the patch, or a problem with the environment?

@unbornchikken
Copy link
Member

You can ignore AppVeyor's log, thats because of iojs.exe instead of node.exe issue. Travis should work with 0.10 and 0.12. With io.js it will fail because 3.x support is blocked because of ref module is not yet implemented its NAN 2.0 support.


#else

/* "Ken Thompson has an automobile which he helped design..." */
Copy link
Member

Choose a reason for hiding this comment

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

Why is this part necessary out of curiosity?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Depends how you define "necessary".

I think dlerror() is an extremely bad design, but it is a POSIX standard. The question becomes how hard to you want to work to implement it on Windows.

I'd be happy with my original implementation (always returning "?"), because IMHO, nobody should be relying on dlerror() to begin with.

The current implementation provides standard-compliant dlerror() functionality by returning a string with the Win32 error code (which can be looked up in WinError.h if ever needed).

What I didn't want to do is return the actual Win32 error text. Win32 error messages can be verbose. I'd either have to allocate a buffer that nobody will free (see also: memory leak), or create a large static buffer. For what? A message nobody should be relying on.

Copy link
Member

Choose a reason for hiding this comment

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

Well the basic implementation above seems adequate to me, and with the #if above this is dead code. Maybe remove to avoid future confusion?

@TooTallNate
Copy link
Member

I'm 👍 for this, but ya we'll have to make sure all the tests are in order. It could be technically considered a breaking change for Windows users who might have been depending on the previous null behavior, but I'm contemplating whether we can consider it a bug fix instead since the behavior was incorrect from the get-go.

Created ExportedFunction() with C naming and calling conventions,
which dynamic_library.js can use to to test symbol lookup.
The function is never actually called.
Also added some additional comments about Windows, with note on how
the test case could become invalid in the future.
@unbornchikken
Copy link
Member

Cool, it's finally ready. I try to make a NAN 2.0 / io.js 3.0 support PR to ref module on this week, and travis is gonna be happy again.

(But I'll miss the reference to Ken Thompson's automobile :-)).
@unbornchikken
Copy link
Member

I'll merge this once NAN 2.0 PR gets ready (after this gets landed: TooTallNate/ref#33), and we can release those together with all tests passed on Travis.

@TooTallNate
Copy link
Member

I have this merged in the v2 branch. v0.10 seems to be failing one test. See https://ci.appveyor.com/project/TooTallNate/node-ffi/build/80. @mcnameej Any ideas there?

[00:01:36]   1) Library should accept `null` as a first argument:
[00:01:36]      Error: Dynamic Symbol Retrieval Error: Win32 error 127
[00:01:36]       at DynamicLibrary.get (C:\projects\node-ffi\lib\dynamic_library.js:112:11)
[00:01:36]       at C:\projects\node-ffi\lib\library.js:50:19
[00:01:36]       at Array.forEach (native)
[00:01:36]       at new Library (C:\projects\node-ffi\lib\library.js:47:28)
[00:01:36]       at Context.<anonymous> (C:\projects\node-ffi\test\library.js:33:22)
[00:01:36]       at callFn (C:\projects\node-ffi\node_modules\mocha\lib\runnable.js:289:21)
[00:01:36]       at Test.Runnable.run (C:\projects\node-ffi\node_modules\mocha\lib\runnable.js:282:7)
[00:01:36]       at Runner.runTest (C:\projects\node-ffi\node_modules\mocha\lib\runner.js:419:10)
[00:01:36]       at C:\projects\node-ffi\node_modules\mocha\lib\runner.js:526:12
[00:01:36]       at next (C:\projects\node-ffi\node_modules\mocha\lib\runner.js:340:14)
[00:01:36]       at C:\projects\node-ffi\node_modules\mocha\lib\runner.js:350:7
[00:01:36]       at next (C:\projects\node-ffi\node_modules\mocha\lib\runner.js:283:14)
[00:01:36]       at Object._onImmediate (C:\projects\node-ffi\nod
[00:01:36] e_modules\mocha\lib\runner.js:318:5)

@mcnameej
Copy link
Contributor Author

mcnameej commented Sep 1, 2015

@TooTallNate: The problem was that older versions of node.exe don't export a node_module_register function. I changed the test to use uv_fs_open instead. PR #232 contains the fix for v2 branch.

@TooTallNate
Copy link
Member

Merged. Thanks @mcnameej!

@mcnameej mcnameej deleted the simple-dlfcn branch September 5, 2015 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

node-ffi claims MIT license, but deps/dlfcn-win32 uses LGPL
3 participants