NppPresage epic

While working on NppPresage, the Notepad++ predictive text plugin I am writing, I ran into an interesting problem which led me on a journey of discovery of some useful and powerful Windows debugging tools.

The problem started occuring when testing my NppPresage plugin with the latest build of Notepad++. After exiting Notepad++, the following error message box would appear, when the NppPresage plugin is installed:

Microsoft Visual C++ Runtime Library

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

The problem was easily reproducible:

  • install the latest Notepad++ release: http://notepad-plus-plus.org/download/ (tested with v5.9.8 Unicode)
  • install the beta presage build: https://sourceforge.net/projects/presage/files/presage/0.8.8b/win32/presage-0.8.8b-20120211-setup.exe/download
  • start Notepad++ and then exit it

I tried disabling the other plugins that are bundled with Notepad++ by moving each plugin individually from "/plugins" to the "/plugins/disabled" directory.
I noticed that disabling NppFTP plugin would not trigger the error above on exitting Notepad++. It appeared that the issue was triggered by some interaction between NppPresage and NppFTP plugins when notepad++ shuts down.

I thought it would be a good idea to prod the collective knowledge of the Notepad++ plugin development list for advice on how to best tackle and solve this issue: http://sourceforge.net/projects/notepad-plus/forums/forum/482781/topic/5012256

I immediately received some helpful comments and suggestions, which I implemented. Unfortunately, these changes did not fix the runtime error.

So I built Notepad++ and NppPresage in debug mode and did a bit of debugging with Visual Studio... I found out that the runtime error occured after execution of commandMenuCleanUp() and before execution of pluginCleanUp(). The runtime error occured after returning from the winmain.cpp:WinMain() function in Notepad++.

I tried was to isolate whether commandMenuCleanUp() and pluginCleanUp() functions were the culprits. Firstly, I put ::MessageBox() calls on function entering/existing. This showed that the commandMenuCleanup() was entered and exited, then the runtime error occured, and then the pluginCleanUp() function was entered and exited.

pluginCleanUp() was not causing the runtime error; its execution follows the runtime error message. I revisited the implementation of pluginCleanUp() to make DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH mirrors of each other. I moved code out of pluginCleanUp() into the NPPN_SHUTDOWN handler.

I spent some more time debugging this problem with the Visual Studio debugger, however this didn't prove very helpful. The runtime error occurs after returning from the Notepad++ main function winmain.cpp:WinMain().

I then turned to WinDbg to gather more information. I debugged the Notepad++ process until the Microsoft Visual C++ Runtime Library error message box appear. Here's the stack trace of all threads just before I click the OK button on the "Microsoft Visual C++ Runtime Library" error dialog box:

0:005> ~* kp

   0  Id: 15bc.1f6c Suspend: 1 Teb: 00000000`7efdb000 Unfrozen
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\SYSTEM32\wow64cpu.dll - 
Child-SP          RetAddr           Call Site
00000000`0008ebf8 00000000`74672d92 wow64cpu!TurboDispatchJumpAddressEnd+0x690
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\SYSTEM32\wow64.dll - 
00000000`0008ec00 00000000`7440d07e wow64cpu!TurboDispatchJumpAddressEnd+0x649
00000000`0008ecc0 00000000`7440c549 wow64!Wow64SystemServiceEx+0x1ce
00000000`0008ed10 00000000`7700ae27 wow64!Wow64LdrpInitialize+0x429
00000000`0008f260 00000000`77007168 ntdll!LdrGetKnownDllSectionHandle+0x1a7
00000000`0008f760 00000000`76ff2aae ntdll!RtlInitCodePageTable+0xe8
00000000`0008f7d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

   1  Id: 15bc.39b0 Suspend: 1 Teb: 00000000`7efd8000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`0066e7e8 00000000`7442a2df ntdll!NtWaitForWorkViaWorkerFactory+0xa
00000000`0066e7f0 00000000`7440cf87 wow64!Wow64EmulateAtlThunk+0x1c97f
00000000`0066e840 00000000`7467276d wow64!Wow64SystemServiceEx+0xd7
00000000`0066f100 00000000`7440d07e wow64cpu!TurboDispatchJumpAddressEnd+0x24
00000000`0066f1c0 00000000`7440c549 wow64!Wow64SystemServiceEx+0x1ce
00000000`0066f210 00000000`7703bde7 wow64!Wow64LdrpInitialize+0x429
00000000`0066f760 00000000`76ff2aae ntdll!LdrGetProcedureAddress+0x24117
00000000`0066f7d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

   2  Id: 15bc.45c4 Suspend: 1 Teb: 00000000`7efd5000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`022ce7e8 00000000`7442a2df ntdll!NtWaitForWorkViaWorkerFactory+0xa
00000000`022ce7f0 00000000`7440cf87 wow64!Wow64EmulateAtlThunk+0x1c97f
00000000`022ce840 00000000`7467276d wow64!Wow64SystemServiceEx+0xd7
00000000`022cf100 00000000`7440d07e wow64cpu!TurboDispatchJumpAddressEnd+0x24
00000000`022cf1c0 00000000`7440c549 wow64!Wow64SystemServiceEx+0x1ce
00000000`022cf210 00000000`7703bde7 wow64!Wow64LdrpInitialize+0x429
00000000`022cf760 00000000`76ff2aae ntdll!LdrGetProcedureAddress+0x24117
00000000`022cf7d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

   3  Id: 15bc.476c Suspend: 1 Teb: 00000000`7efaa000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`03d3f0f8 00000000`7467282c wow64cpu!TurboDispatchJumpAddressEnd+0x690
00000000`03d3f100 00000000`7440d07e wow64cpu!TurboDispatchJumpAddressEnd+0xe3
00000000`03d3f1c0 00000000`7440c549 wow64!Wow64SystemServiceEx+0x1ce
00000000`03d3f210 00000000`7703bde7 wow64!Wow64LdrpInitialize+0x429
00000000`03d3f760 00000000`76ff2aae ntdll!LdrGetProcedureAddress+0x24117
00000000`03d3f7d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

   4  Id: 15bc.2600 Suspend: 1 Teb: 00000000`7efad000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`03cde7e8 00000000`7442a2df ntdll!NtWaitForWorkViaWorkerFactory+0xa
00000000`03cde7f0 00000000`7440cf87 wow64!Wow64EmulateAtlThunk+0x1c97f
00000000`03cde840 00000000`7467276d wow64!Wow64SystemServiceEx+0xd7
00000000`03cdf100 00000000`7440d07e wow64cpu!TurboDispatchJumpAddressEnd+0x24
00000000`03cdf1c0 00000000`7440c549 wow64!Wow64SystemServiceEx+0x1ce
00000000`03cdf210 00000000`7703bde7 wow64!Wow64LdrpInitialize+0x429
00000000`03cdf760 00000000`76ff2aae ntdll!LdrGetProcedureAddress+0x24117
00000000`03cdf7d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

#  5  Id: 15bc.1650 Suspend: 1 Teb: 00000000`7efa7000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`03dcfc78 00000000`770b9218 ntdll!DbgBreakPoint
00000000`03dcfc80 00000000`770224cd ntdll!DbgUiRemoteBreakin+0x38
00000000`03dcfcb0 00000000`00000000 ntdll!LdrGetProcedureAddress+0xa7fd

Based on the above, no threads are executing in Notepad++ or NppPresage code. This confirms the observation obtained with Visual Studio debugger. Unfortunately, this does not provide any clues as to what is causing the issue. !analyze -v is not helpful either.

After clicking the OK button on the "Microsoft Visual C++ Runtime Library" error dialog box, this is the stack trace:

0:000> ~* kp

.  0  Id: 15bc.1f6c Suspend: 0 Teb: 00000000`7efdb000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`0008e308 00000000`7441601a ntdll!ZwTerminateProcess+0xa
00000000`0008e310 00000000`7440cf87 wow64!Wow64EmulateAtlThunk+0x86ba
00000000`0008e340 00000000`7467276d wow64!Wow64SystemServiceEx+0xd7
00000000`0008ec00 00000000`7440d07e wow64cpu!TurboDispatchJumpAddressEnd+0x24
00000000`0008ecc0 00000000`7440c549 wow64!Wow64SystemServiceEx+0x1ce
00000000`0008ed10 00000000`7700ae27 wow64!Wow64LdrpInitialize+0x429
00000000`0008f260 00000000`77007168 ntdll!LdrGetKnownDllSectionHandle+0x1a7
00000000`0008f760 00000000`76ff2aae ntdll!RtlInitCodePageTable+0xe8
00000000`0008f7d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

Not much to go on from here.

I then tried to debug the problem with Dependency Walker. I used the profiling feature of depends (Profile->Start Profiling) to look at all the dependencies, including the dynamically loaded Notepad++ plugins and their dependents. This is where I found out something interesting... before delving into it, I should note that the NppPresage plugin depends on the presage library, which is built with MinGW/MSYS and hence depends on the MinGW standard runtime libs libstdc++-6.dll and libgcc_s_dw2-1.dll.

I profiled Notepad++ in the following three scenarios:
a) Notepad++ with both NppFTP and NppPresage installed
b) Notepad++ with NppFTP plugin installed (no NppPresage)
c) Notepad++ with NppPresage plugin installed (no NppFTP)

Let's start with scenario a) Notepad++ with both NppFTP and NppPresage installed...

Here's a snippet of the profiling log output:

LoadLibraryW("c:\program files (x86)\notepad++\plugins\NppPresage.dll") called from "c:\program files (x86)\notepad++\NOTEPAD++.EXE" at address 0x0046FF7A.
Loaded "c:\program files (x86)\notepad++\plugins\NPPPRESAGE.DLL" at address 0x71900000.  Successfully hooked module.
DllMain(0x71900000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\notepad++\plugins\NPPPRESAGE.DLL" called.

...snip...

LoadLibraryW("libpresage-1.dll") called from "c:\program files (x86)\notepad++\plugins\NPPPRESAGE.DLL" at address 0x71901D7A.
Loaded "c:\program files (x86)\presage\bin\LIBPRESAGE-1.DLL" at address 0x03C80000.  Successfully hooked module.
Loaded "c:\program files (x86)\presage\bin\LIBSTDC++-6.DLL" at address 0x6FC40000.  Successfully hooked module.
Loaded "c:\program files (x86)\presage\bin\LIBGCC_S_DW2-1.DLL" at address 0x6E940000.  Successfully hooked module.
Loaded "c:\program files (x86)\presage\bin\LIBSQLITE3-0.DLL" at address 0x66380000.  Successfully hooked module.
DllMain(0x6E940000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\presage\bin\LIBGCC_S_DW2-1.DLL" called.
GetProcAddress(0x6E940000 [c:\program files (x86)\presage\bin\LIBGCC_S_DW2-1.DLL], "__register_frame_info") called from "c:\program files (x86)\presage\bin\LIBGCC_S_DW2-1.DLL" at address 0x6E9411D7 and returned 0x6E955DA8.
DllMain(0x6E940000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\presage\bin\LIBGCC_S_DW2-1.DLL" returned 1 (0x1).
DllMain(0x6FC40000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\presage\bin\LIBSTDC++-6.DLL" called.
GetProcAddress(0x6E940000 [c:\program files (x86)\presage\bin\LIBGCC_S_DW2-1.DLL], "__register_frame_info") called from "c:\program files (x86)\presage\bin\LIBSTDC++-6.DLL" at address 0x6FC411D7 and returned 0x6E955DA8.
DllMain(0x6FC40000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\presage\bin\LIBSTDC++-6.DLL" returned 1 (0x1).
DllMain(0x66380000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\presage\bin\LIBSQLITE3-0.DLL" called.
GetProcAddress(0x6E940000 [c:\program files (x86)\presage\bin\LIBGCC_S_DW2-1.DLL], "__register_frame_info") called from "c:\program files (x86)\presage\bin\LIBSQLITE3-0.DLL" at address 0x663811D7 and returned 0x6E955DA8.
DllMain(0x66380000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\presage\bin\LIBSQLITE3-0.DLL" returned 1 (0x1).
DllMain(0x03C80000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\presage\bin\LIBPRESAGE-1.DLL" called.
GetProcAddress(0x6E940000 [c:\program files (x86)\presage\bin\LIBGCC_S_DW2-1.DLL], "__register_frame_info") called from "c:\program files (x86)\presage\bin\LIBPRESAGE-1.DLL" at address 0x03C811D7 and returned 0x6E955DA8.
DllMain(0x03C80000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\presage\bin\LIBPRESAGE-1.DLL" returned 1 (0x1).
LoadLibraryW("libpresage-1.dll") returned 0x03C80000.

...snip...

DllMain(0x71900000, DLL_PROCESS_ATTACH, 0x00000000) in "c:\program files (x86)\notepad++\plugins\NPPPRESAGE.DLL" returned 1 (0x1).
LoadLibraryW("c:\program files (x86)\notepad++\plugins\NppPresage.dll") returned 0x71900000.

The above snippet reveals that the dependants of NppPresage.dll (LIBPRESAGE-1.DLL, LIBSQLITE3-0.DLL, LIBSTDC++-6.DLL, LIBGCC_S_DW2-1.DLL) are all loaded and they all read the address of "__register_frame_info" function from the LIBGCC_S_DW2-1.DLL module.

Continuing with the profiling, after exiting the Notepad++, the log shows that the DLLs are detached. When we come to unloading the NppFTP.DLL module, the following very interesting output is logged:

DllMain(0x6A140000, DLL_PROCESS_DETACH, 0x00000000) in "c:\program files (x86)\notepad++\plugins\NPPFTP.DLL" called.
GetProcAddress(0x6E940000 [c:\program files (x86)\presage\bin\LIBGCC_S_DW2-1.DLL], "__deregister_frame_info") called from "c:\program files (x86)\notepad++\plugins\NPPFTP.DLL" at address 0x6A141223 and returned 0x6E9565C0.
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.

At this time, the usual "Microsoft Visual C++ Runtime Library" error message box appears. It is interesting to note that the NPPFTP.DLL module gets the proc address of "__deregister_frame_info". However, looking at the log output corresponding to the loading of the NppFTP.DLL module, it is clear that the NPPFTP.DLL module did not get the address of the "__register_frame_info" function.

The order of events is as follows:
- NPPFTP.DLL is attached (no call is made to retrieve "__register_frame_info")
- NPPPRESAGE.DLL is attached (dependants retrieve address "__register_frame_info")
- NPPFTP.DLL is detached (call is made to retrieve address "__deregister_frame_info")
- NPPPRESAGE.DLL is detached (dependants retrieve address "__deregister_frame_info")

Based on the information above, I formulated the following working hypothesis:

NppFTP module calls "__deregister_frame_info" because the LIBGCC_S_DW2-1.DLL module is loaded, without having previously called the "__register_frame_info" function.

Let's profile Scenario b) Notepad++ with NppFTP plugin installed (no NppPresage).
In this scenario, the runtime error does not occur.
The log reveals that the address of neither "__register_frame_info" nor "__deregister_frame_info" is read. No GetProcAddress() calls to read those symbols are made.

Let's now profile Scenario c) Notepad++ with NppPresage plugin installed (no NppFTP).
In this scenario, the runtime error does not occur.
The output log shows that the NPPPRESAGE.DLL dependants load the address of "__register_frame_info" and "__deregister_frame_info".

The next step I took was to figure out if NPPFTP.DLL module would load the address of "__register_frame_info" if the LIBGCC_S_DW2-1.DLL module was loaded at attach time. To test this, I renamed NPPPRESAGE.DLL to NPPEPRESAGE.DLL, so that NPPEPRESAGE.DLL would be attached before NPPFTP.DLL.
In this case (let's call it Scenario d), NPPFTP.DLL module indeed calls reads the address of "__register_frame_info". NPPEPRESAGE.DLL is detached prior to NPPFTP.DLL, no log of GetProcAddress() to read the "__deregister_frame_info" symbol appears.

(BTW, this made me wonder whether the Notepad++ plugins should be unloaded in the reverse order in which they are loaded.)

Time to fire up WinDBG again... this time with a better idea what to look for!

I located and put breakpoints on the "__register_frame_info" and "__deregister_frame_info" symbols:

0:000> x libgcc_s_dw2_1!*frame_info*
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\SYSTEM32\wow64.dll - 
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\presage\bin\libgcc_s_dw2-1.dll - 
00000000`6e955c64 libgcc_s_dw2_1!_register_frame_info_bases ()
00000000`6e955da8 libgcc_s_dw2_1!_register_frame_info ()
00000000`6e95604c libgcc_s_dw2_1!_register_frame_info_table_bases ()
00000000`6e956188 libgcc_s_dw2_1!_register_frame_info_table ()
00000000`6e95640c libgcc_s_dw2_1!_deregister_frame_info_bases ()
00000000`6e9565c0 libgcc_s_dw2_1!_deregister_frame_info ()

0:000> bu libgcc_s_dw2_1!_register_frame_info
0:000> bu libgcc_s_dw2_1!_deregister_frame_info

and restarted the debugged process.

On startup, the _register_frame_info breakpoint was hit four times (by the NPPPRESAGE.DLL dependants calling it. Note that it was not called by NPPFTP module).
On Notepad++ exit, the breakpoint was hit and the following stack trace shows that the NppFTP module called on _deregister_frame_info():

Breakpoint 1 hit
libgcc_s_dw2_1!_deregister_frame_info:
6e9565c0 55              push    ebp
0:000:x86> kp
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\Notepad++\plugins\NppFTP.dll - 
ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
001413d8 6a141233 libgcc_s_dw2_1!_deregister_frame_info
001413f8 6a14102f NppFTP+0x1233
00141408 6a1410f5 NppFTP+0x102f
00141428 771d99a0 NppFTP+0x10f5
00141448 771faefb ntdll32!RtlQueryEnvironmentVariable+0x241
001414d0 771e1291 ntdll32!LdrRemoveLoadAsDataTable+0x5e2
00141514 75052312 ntdll32!LdrUnloadDll+0x4a
00141524 00436b6b KERNELBASE!FreeLibrary+0x15
003a3610 a1660469 npp+0x36b6b
003a3614 6a14fca0 0xa1660469
003a3618 6a14fcc0 NppFTP!setInfo
003a361c 6a14fd94 NppFTP!getName
003a3620 6a14ff9c NppFTP!beNotified
003a3624 6a14fccc NppFTP!getFuncsArray
003a3628 6a14fcd8 NppFTP!messageProc
003a362c 6a2c3060 NppFTP!isUnicode
003a3630 00000000 NppFTP!getFuncsArray+0x1730c4

Debugging with gdb into the MinGW libgcc_s_dw2_1 DLL shows the same behaviour:

(gdb) b _deregister_frame_info
No symbol table is loaded.  Use the "file" command.
Make breakpoint pending on future shared library load? (y or [n]) y

Breakpoint 1 (_deregister_frame_info) pending.
(gdb) r
Starting program: c:/Program Files (x86)/Notepad++/notepad++.exe
[New Thread 18636.0x3970]
[New Thread 18636.0x4408]
[New Thread 18636.0x471c]
[New Thread 18636.0x43c8]
[New Thread 18636.0x20f4]
[New Thread 18636.0x3560]

Breakpoint 1, 0x6e9565c6 in libgcc_s_dw2-1!__deregister_frame_info ()
   from C:\Program Files (x86)\presage\bin\libgcc_s_dw2-1.dll
(gdb) bt
#0  0x6e9565c6 in libgcc_s_dw2-1!__deregister_frame_info ()
   from C:\Program Files (x86)\presage\bin\libgcc_s_dw2-1.dll
#1  0x6a141233 in ?? ()
   from c:\Program Files (x86)\Notepad++\plugins\NppFTP.dll
#2  0x6a14102f in ?? ()
   from c:\Program Files (x86)\Notepad++\plugins\NppFTP.dll
#3  0x6a1410f5 in ?? ()
   from c:\Program Files (x86)\Notepad++\plugins\NppFTP.dll
#4  0x771d99a0 in ntdll!RtlpNtSetValueKey ()
   from C:\Windows\system32\ntdll.dll
#5  0x6a140000 in ?? ()
#6  0x771faefb in ntdll!RtlCreateServiceSid ()
   from C:\Windows\system32\ntdll.dll
#7  0x6a141060 in ?? ()
   from c:\Program Files (x86)\Notepad++\plugins\NppFTP.dll
#8  0x771e1291 in ntdll!LdrLoadAlternateResourceModule ()
   from C:\Windows\system32\ntdll.dll
#9  0x6a140000 in ?? ()
#10 0x75052312 in KERNELBASE!FreeSid ()
   from C:\Windows\syswow64\KernelBase.dll
#11 0x00436b6b in ?? ()
#12 0x12e0039b in ?? ()
#13 0x6a14fca0 in ?? ()
   from c:\Program Files (x86)\Notepad++\plugins\NppFTP.dll
#14 0x00000003 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

This is where NPPFTP calls into _deregister_frame_info() and later causes the runtime error. Stepping through the code, we eventually get to the point where the runtime error occurs:

(gdb) n
Single stepping until exit from function libgcc_s_dw2-1!__emutls_register_common
,
which has no line number information.
[New Thread 17712.0x1530]
0x74e68e53 in msvcrt!abort () from C:\Windows\syswow64\msvcrt.dll
(gdb)
Single stepping until exit from function msvcrt!abort,
which has no line number information.
warning: Invalid parameter passed to C runtime function.

warning: Invalid parameter passed to C runtime function.

0x74e65ccd in msvcrt!atexit () from C:\Windows\syswow64\msvcrt.dll

So, it looks like libgcc_s_dw2-1!__emutls_register_common is calling into msvcrt!abort.
This is the cause of the runtime error!

Continuing on, we get to the NPPPRESAGE.DLL dependants executing _deregister_frame_info() in turn (only showing libpresage-1.dll below):

Breakpoint 1, 0x6e9565c6 in libgcc_s_dw2-1!__deregister_frame_info ()
   from C:\Program Files (x86)\presage\bin\libgcc_s_dw2-1.dll
(gdb) bt
#0  0x6e9565c6 in libgcc_s_dw2-1!__deregister_frame_info ()
   from C:\Program Files (x86)\presage\bin\libgcc_s_dw2-1.dll
#1  0x04091273 in __gcc_deregister_frame ()
   from C:\Program Files (x86)\presage\bin\libpresage-1.dll
#2  0x04091086 in __dll_exit ()
   from C:\Program Files (x86)\presage\bin\libpresage-1.dll
#3  0x0409110a in DllMainCRTStartup@12 ()
   from C:\Program Files (x86)\presage\bin\libpresage-1.dll
#4  0x771d99a0 in ntdll!RtlpNtSetValueKey ()
   from C:\Windows\system32\ntdll.dll
#5  0x04090000 in ?? ()
#6  0x771ed6ba in ntdll!TpSetPoolStackInformation ()
   from C:\Windows\system32\ntdll.dll
#7  0x040910c0 in __dll_exit ()
   from C:\Program Files (x86)\presage\bin\libpresage-1.dll
#8  0x771ed55c in ntdll!TpSetPoolStackInformation ()
   from C:\Windows\system32\ntdll.dll
#9  0x00000002 in ?? ()
#10 0x00000000 in ?? ()

until the process terminates.

So, the question to answer is: why is NPPFTP module calling into libgcc_s_dw2-1!__deregister_frame_info on DLL_PROCESS_DETACH?
To answer that, I grabbed the latest NppFTP sources from the NppFTP Subversion repository (https://nppftp.svn.sourceforge.net/svnroot/nppftp) and built NppFTP in debug mode using Code::Blocks 10.05 with MinGW.

I could not reproduce the problem with this debug build of NppFTP.
I built NppFTP in release mode and that also did not reproduce the runtime error problem.

So, it appeared that the runtime error in NppFTP disappeared by rebuilding the latest NppFTP sources with Code::Blocks 10.05 with MinGW.

I got in touch with the author of NppFTP to inform him of all the above. I also took the opportunity to send in a patch to resolve a memory access violation that I discovered with WinDBG, gdb and Application Verifier. The main issue I discovered was with class FTPProfile and class RefObject. FTPProfile inherits from RefObject... I guessed the intent was to endow FTPProfile objects with smart pointer functionality, however, there were a couple of issues with the implementation:

34 int RefObject::Release() {
35     m_refcounter--;
36     if (!m_refcounter)
37         delete this;
38     return m_refcounter;
39 }

The code above deletes the object at line 37, and then tries to read m_refcounter data member of the object that was just deleted. This caused a memory access violation error.

The NppFTP author graciously accepted my patch and acknoledged the runtime error problem.

I am looking forward to the next release of Notepad++ and NppFTP. NppPresage will be a blast by then (provided I manage to find some free time to work on it)!