Crash in LexActivator 3.12.0/3.12.1

I’m using the 3.12.0 Visual Studio 2015 static lib version of LexActivator on Windows 10, and today when I started and rather quickly stopped our internal development test application (compiled in debug mode), it crashed. I assume it was in the setup of e.g. the LexActivator server pingback thread, seeing callstack entries like LexSystemInfo::GetVmName? I’ve collected the details below. Note though that I was stress testing the app a bit here, but that shouldn’t be an excuse for the LexActivator threads I hope? We do set a LicenseCallback function, though it doesn’t do much atm apart from SetLicenseCallback(nullptr) after the 1st callback.

Again, I don’t know for sure that this is a genuine defect or if it was caused by me fooling around, but you may want to look into it, if only to make it more fool-proof :slight_smile:

The exception:
Exception thrown at 0x00007FFC8C56A691 (msvcp140d.dll) in Test-Environment.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF. occurred

The callstack:

  1. msvcp140d.dll!00007ffc8c56a691()
  2. Test-Environment.exe!std::basic_filebuf<char,std::char_traits >::_Initcvt(const std::codecvt<char,char,_Mbstatet> * _Newpcvt) Line 685 at c:\program files (x86)\microsoft visual studio 14.0\vc\include\fstream(685)
  3. Test-Environment.exe!std::basic_filebuf<char,struct std::char_traits >::open(wchar_t const *,int,int)
  4. Test-Environment.exe!std::basic_ifstream<char,struct std::char_traits>::basic_ifstream<char,struct std::char_traits >(wchar_t const *,int,int)
  5. Test-Environment.exe!LexExecute(class std::basic_string<char,struct std::char_traits,class std::allocator >)
  6. Test-Environment.exe!GetVm(void)
  7. Test-Environment.exe!LexSystemInfo::GetVmName(void)
  8. Test-Environment.exe!LexActivationService::GetActivationRequest(class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::basic_string<char,struct std::char_traits,class std::allocator >,class UserCredential,class std::vector<class Metadata,class std::allocator >,class std::vector<class ActivationMeterAttribute,class std::allocator >)
  9. Test-Environment.exe!LexActivationService::ActivateFromServer(class std::basic_string<char,struct std::char_traits,class std::allocator >,class ProductDataDto,class ActivationPayload &,class UserCredential &,class std::vector<class ActivationMeterAttribute,class std::allocator >,bool)
  10. Test-Environment.exe!ThreadTimerCallback(void *,unsigned char)
  11. ntdll.dll!00007ffca4312489()
  12. ntdll.dll!00007ffca430e869()
  13. ntdll.dll!00007ffca42e276a()
  14. kernel32.dll!00007ffca30c7034()
  15. ntdll.dll!00007ffca431cec1()

Source code for the only callstack entry which VS could find code for (entry 2), in MSVC header file “fstream”;

void _Initcvt(const _Cvt *_Newpcvt)
    {	// initialize codecvt pointer
    if (_Newpcvt->always_noconv())
        _Pcvt = 0;	// nothing to do
    else
        {	// set up for nontrivial codecvt facet
        _Pcvt = _Newpcvt;
        _Mysb::_Init();	// reset any buffering
        }
    }

Hi Carl,

Setting the pointer to null can cause undefined behavior. Can you see if you can replicate the issue in v3.12.1 with and without setting the callback to null.

Well, the problem is I immediately tried, but I can’t replicate it even with 3.12.0…

Like I said: it might be a fluke, or it might be a stressful situation which caused it, but the only thing I’m sure of was that I started and immediately stopped the app again. On this machine the LexActivator initialization calls take about 1 second, and I assume the app stopped right after that (with an Alt-F4 already in the keyboard buffer during that 1st second).

And setting the callback to nullptr has worked so far for us (I think/hope?) I didn’t realize it was a no-no? Should I instead just have an internal bool which checks if it’s the very 1st callback and just do nothing after that 1st one, but leave the callback itself intact?

Oh – one more possibly damning circumstance: we do the initial Cryptlex setup (SetProductData, SetProductId, SetAppVersion, SetLicenseCallback) from the ‘main’ thread, while the very first IsLicenseGenuine and ActivateLicense and such are performed almost immediately afterwards from another thread (a helper worker thread). (We’re plugins and we’re not allowed to perform a leisurely init.)

The crash was not caused due to it being set to the null ptr. Setting it to null immediately after callback finishes is safe.

I would recommend trying it with v3.12.1 as it completely drops the dependency on cmd (which was used for some tasks).

You can call IsLicenseGenuine() in the main thread as it is not blocking. ActivateLicense() is a good candidate to be called in a separate thread as it is a blocking call.

Thanks for that!

But while IsLicenseGenuine may not be really blocking, it does take ~1 second on most machines we tested. The host app calls our plugins one at a time while also displaying the plugin’s name in it’s splash screen. And since we have a suite of 70+ plugins… you get the idea :slight_smile:

Success; using 3.12.0 I got another crash when quickly stopping our test app when it has just started up.

The exception again is an identical access violation;
Exception thrown at 0x00007FFC7F3DA691 (msvcp140d.dll) in Test-Environment.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

This time the callstack is:

1. msvcp140d.dll!00007ffc7f3da691() Unknown
2. Test-Environment.exe!std::basic_filebuf<char,std::char_traits >::_Initcvt(const std::codecvt<char,char,_Mbstatet> * _Newpcvt) Line 685 C++
3. Test-Environment.exe!std::basic_filebuf<char,struct std::char_traits >::open(wchar_t const *,int,int) Unknown
4. Test-Environment.exe!std::basic_ifstream<char,struct std::char_traits >::basic_ifstream<char,struct std::char_traits >(wchar_t const *,int,int) Unknown
5. Test-Environment.exe!LexExecute(class std::basic_string<char,struct std::char_traits,class std::allocator >) Unknown
6. Test-Environment.exe!GetOSVersion(void) Unknown
7. Test-Environment.exe!LexSystemInfo::GetOsVersion(void) Unknown
8. Test-Environment.exe!LexActivationService::GetActivationRequest(class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::basic_string<char,struct std::char_traits,class std::allocator >,class UserCredential,class std::vector<class Metadata,class std::allocator >,class std::vector<class ActivationMeterAttribute,class std::allocator >) Unknown
9. Test-Environment.exe!LexActivationService::ActivateFromServer(class std::basic_string<char,struct std::char_traits,class std::allocator >,class ProductDataDto,class ActivationPayload &,class UserCredential &,class std::vector<class ActivationMeterAttribute,class std::allocator >,bool) Unknown
10. Test-Environment.exe!ThreadTimerCallback(void *,unsigned char) Unknown
11. ntdll.dll!00007ffca4312489() Unknown
12. ntdll.dll!00007ffca430e869() Unknown
13. ntdll.dll!00007ffca42e276a() Unknown
14. kernel32.dll!00007ffca30c7034() Unknown
15. ntdll.dll!00007ffca431cec1() Unknown

I’ll try testing with 3.12.1, though t takes many timing-perfect calls to get it to crash, so me not being able to trigger it might not mean much I’m afraid…

Alas… Using 3.12.1 I can also get it to crash, twice by now. Though this time it wasn’t in fstream anymore (fstream because of reading cmd’s response from stdin?), but I got this:

Exception (identical both times):
Exception thrown at 0x00007FFCA4315E16 (ntdll.dll) in Test-Environment.exe: 0xC0000005: Access violation writing location 0x0000000000000024.

Call stack 1:

  1. ntdll.dll!00007ffca4315e16() Unknown
  2. ntdll.dll!00007ffca42f15b4() Unknown
  3. ntdll.dll!00007ffca42f13e2() Unknown
  4. Test-Environment.exe!_Init_thread_lock() Line 121 C++
  5. Test-Environment.exe!_Init_thread_footer(int * pOnce) Line 220 C++
  6. Test-Environment.exe!GetSystemHostname(void) Unknown
  7. Test-Environment.exe!LexSystemInfo::GetHostname(void) Unknown
  8. Test-Environment.exe!LexActivationService::GetActivationRequest(class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::basic_string<char,struct std::char_traits,class std::allocator >,class UserCredential,class std::vector<class Metadata,class std::allocator >,class std::vector<class ActivationMeterAttribute,class std::allocator >) Unknown
  9. Test-Environment.exe!LexActivationService::ActivateFromServer(class std::basic_string<char,struct std::char_traits,class std::allocator >,class ProductDataDto,class ActivationPayload &,class UserCredential &,class std::vector<class ActivationMeterAttribute,class std::allocator >,bool) Unknown
  10. Test-Environment.exe!ThreadTimerCallback(void *,unsigned char) Unknown
  11. ntdll.dll!00007ffca4312489() Unknown
  12. ntdll.dll!00007ffca430e869() Unknown
  13. ntdll.dll!00007ffca42e276a() Unknown
  14. kernel32.dll!00007ffca30c7034() Unknown
  15. ntdll.dll!00007ffca431cec1() Unknown

Call stack 2:

  1. ntdll.dll!00007ffca4315e16() Unknown
  2. ntdll.dll!00007ffca42f15b4() Unknown
  3. ntdll.dll!00007ffca42f13e2() Unknown
  4. Test-Environment.exe!_Init_thread_lock() Line 121 C++
  5. Test-Environment.exe!_Init_thread_footer(int * pOnce) Line 220 C++
  6. Test-Environment.exe!GetSystemHostname(void) Unknown
  7. Test-Environment.exe!LexSystemInfo::GetHostname(void) Unknown
  8. Test-Environment.exe!LexActivationService::GetActivationRequest(class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::basic_string<char,struct std::char_traits,class std::allocator >,class UserCredential,class std::vector<class Metadata,class std::allocator >,class std::vector<class ActivationMeterAttribute,class std::allocator >) Unknown
  9. Test-Environment.exe!LexActivationService::ActivateFromServer(class std::basic_string<char,struct std::char_traits,class std::allocator >,class ProductDataDto,class ActivationPayload &,class UserCredential &,class std::vector<class ActivationMeterAttribute,class std::allocator >,bool) Unknown
  10. Test-Environment.exe!ThreadTimerCallback(void *,unsigned char) Unknown
  11. ntdll.dll!00007ffca4312489() Unknown
  12. ntdll.dll!00007ffca430e869() Unknown
  13. ntdll.dll!00007ffca42e276a() Unknown
  14. kernel32.dll!00007ffca30c7034() Unknown
  15. ntdll.dll!00007ffca431cec1() Unknown

We will get back to you on this. Please send this issue to support@cryptlex.com. If possible do include a sample which can help the team to replicate the issue.

Hi Adnan,

I managed to create a test app which crashes rather consistently, and sent it to support. Hopefully this has enough pointers for you guys to fix this issue!

Hi Carl,

We tried to replicate this issue and the crash only occurs when MT build is run using Visual Studio in debug mode.

When we tried to replicate the issue in case of MD build or when MT debug build is run directly (without Visual Studio) we were unable to replicate the issue.

Regards,
Ahmad.

Hi Ahmad,

Thank you for looking into this!

Is there a bug fix underway for this? The multithreaded debug build shows there is a possible pathway in the LexActivator code base which causes a hard crash. It would only be a nuisance when it only occurs in those debug builds, but since this is clearly a timing-sensitive issue, not being able to replicate it under other circumstances doesn’t guarantee it isn’t there under those circumstances…

So I would sleep a lot more comfortable if you could state that you not only replicated the issue albeit only in debug builds, but also found the cause and fixed it, even if only for debug builds.
Or at least that it cannot show in release builds.

After all: (to me) it smells like there’s a detached thread going rogue on resources that are already released because the application has already shut down. And if that thread happens to be the server sync thread instead of just a startup-only fire-and-forget thread then I suppose this issue could not only occur when you quickly shut down the app after starting it (again: timing specific), but also if you just so happen to catch the sync thread off guard when going down just when it became active again…

Hi Carl,

We are tracking this issue and will keep you posted.