Quantcast
Channel: Windows XP Latest Topics
Viewing all articles
Browse latest Browse all 2068

How VS makes working code still incompatible

$
0
0

there was a recent update (my previos version was visual studio 2019 v16.4 updated to vs 2019 v16.10 (the exact version is not known so it must be between those versions)

the code i used is windows xp compatible however this "build in trick" still makes my code still incompatible

in the past your code useally gone to winmain() in some other codes i reconized that some code was added to my executable that actually was not needed at all

so i was wondering why did my executable (what only printed MessageboxA) gone a lot bigger

going after that i could understand that this code was added by something else and is executed before my code in winmain() is executed

in other compilers or maybe settings? you didnt see this problem and it gone to winmain() directly then the executable was smaller too in my test executable it was just MessageboxA function and no need of executing some "other/more" code

this time i had the same problem but this time it made the executable not only inefficient it also made it incompatible
(to see here is that microsoft can add this code before your code and make it lets say windows 10 only "this runtime code then gets executed and says "windows 10 only" or "access denied" before your working code is executed)

 

so i took a look what this code actually does do

all begins with the function that is called before winmain()

extern "C" DWORD WinMainCRTStartup(LPVOID) // <- called before winmain
{

    __security_init_cookie // (unimportant for us)
    return __scrt_common_main(); // <-- calls next functions
}

the filename for this code is exe_winmain.cpp and useally is in a directory (or something close) called
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.24.28314\crt\src\vcruntime\exe_winmain.cpp

CRT means: C runtime, so we actually know what we deal with

in my case it use a unwanted function InitializeCriticalSectionEx (that i actually use nowhere in my code but the c runtime use it)

so i looked how and where it do that

the code cain is as follows:

calls __scrt_common_main ->__scrt_common_main_seh
src\vctools\crt\vcstartup\src\eh\i386\secchk.c
: (call chain)
0, __SEH_prolog4

1, __scrt_initialize_crt // -> has function __cdecl __vcrt_initialize_locks(VS 16.4works with InitializeCriticalSectionEx and InitializeCriticalSectionAndSpinCount)  (VS 16.10 only work with InitializeCriticalSectionEx) -> the VS 16.4 version checks if it can use InitializeCriticalSectionEx if it cant it use InitializeCriticalSectionAndSpinCount (the code use a function called try_get_function() to do so)

VC\Tools\MSVC\14.29.30037\crt\src\vcruntime\locks.cpp

this is the function with more details:

(static void* __cdecl try_get_function(
        function_id      const id,
        char      const* const name,
        module_id const* const first_module_id,
        module_id const* const last_module_id
        ) noexcept )

but that is only important if we want to use InitializeCriticalSectionEx, if we want we just could use InitializeCriticalSectionAndSpinCount and this part would be solved

2, __scrt_acquire_startup_lock

3, _initterm_e (dont have InitializeCriticalSectionEx yet)

(then _initterm is done a second time and has InitializeCriticalSectionEx in internal)

4, _initterm <--- second time without _e

the function "_initterm"

has 2 functions 1 is called __guard_check_icall_fptr (this function checks if the pointer is valid and is unimportant for this case)

the other function calls several functions (__xc_a beginning list of functions and __xc_z (end of functions))

the second function in list of __xc_a has InitializeCriticalSectionEx in internal and is called:

static _Init_lock (is a class constructor) and leads to _Init_locks
_Init_locks is in a file called "xlock.cpp"
folder:
VC\Tools\MSVC\14.29.30037\crt\src\stl\xlock.cpp

(c code)
__thiscall _Init_locks::_Init_locks() noexcept { // initialize locks
    if (InterlockedIncrement(&init) == 0) {
        for (auto& elem : mtx) {
            _Mtxinit(&elem); // <- next step we looking for
        }
    }
}

here we look at function _Mtxinit
filename that contain _Mtxinit "xmtx.cpp" folder:
VC\Tools\MSVC\14.24.28314\crt\src\stl\xmtx.cpp
(c code)
void __CLRCALL_PURE_OR_CDECL _Mtxinit(_Rmtx* _Mtx) noexcept { // initialize mutex
    InitializeCriticalSectionEx(_Mtx, 4000, 0); // this variant
}

here also is the diffrens what has been changed:

void __CLRCALL_PURE_OR_CDECL _Mtxinit(_Rmtx* _Mtx) noexcept { // initialize mutex
    __crtInitializeCriticalSectionEx(_Mtx, 4000, 0); // variant before
}


the function __crtInitializeCriticalSectionEx has a check if it do use InitializeCriticalSectionEx or if it do use InitializeCriticalSectionAndSpinCount (xp compatible)

extern "C" BOOL __cdecl __crtInitializeCriticalSectionEx(
    LPCRITICAL_SECTION const lpCriticalSection, DWORD const dwSpinCount, DWORD const Flags) {
    // use InitializeCriticalSectionEx if it is available (only on Windows Vista+)...
    IFDYNAMICGETCACHEDFUNCTION(
        PFNINITIALIZECRITICALSECTIONEX, InitializeCriticalSectionEx, pfInitializeCriticalSectionEx) {
        return pfInitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, Flags);
    }

    // ...otherwise fall back to using InitializeCriticalSectionAndSpinCount.
    InitializeCriticalSectionAndSpinCount(lpCriticalSection, dwSpinCount);
    return TRUE;
}

 

so even if your entire code would just use a single MessageboxA this CRT or "C runtime" starting/calling WinMainCRTStartup beforehand

makes your application still incompatible, even if your code 100 % would work


noticeable is that "they" can do this not only with a limit to windows vista, 7, 8, 8.1, or 10
they can add incompatible functions to that CRT code
thus you might just upgrade your VS/Compiler and your code wont work even if the code is compatible


its like a check "do this computer have windows 10" -> access denied -> no code is spawned (even tho your code would work)

shame to microsoft for this one

(the other code i tryed has a header file that use c++20 style (it are just type converters like you do with templates) but it doesnt use any windows functions))

in that sence that is a compiler question of the c++ style (type converter) not a "missing api" question, but still that CRT used that api even tho i dont have that InitializeCriticalSectionEx in my code

and to fix up different types such as handles, int, float etc. for example over a template or type converter, again is a compiler question

here is the rest of the callchain (before your code is executed)

5,  __scrt_release_startup_lock
6,  __scrt_get_dyn_tls_init_callback
7,  __scrt_get_dyn_tls_dtor_callback
8 , __scrt_get_show_window_mode
9,  _get_narrow_winmain_command_line
10, WinMain(our executable/our code is then executed) <-- here begins/comes our code/programm/app

so everybody can easy understand why your code got "blocked" or will just maybe in future, so we know the trick beforehand :-)


Viewing all articles
Browse latest Browse all 2068

Trending Articles