Menu

#2014 strtok_s is not linked to a correct version of MSVCRT

WSL
closed
None
Support
invalid
Invalid
False
2014-08-29
2013-08-19
LIU Hao
No

The following C code results in a DLL initialization error:

#include <stdio.h>
#define __STDC_WANT_LIB_EXT1__  1
#include <string.h>

int main(){
    char buff[] = "a,b,c,d,e,f";
    char *ctx, *p = strtok_s(buff, ",", &ctx);
    while(p != 0){
        puts(p);

        p = strtok_s(0, ",", &ctx);
    }
}

Compiled with gcc main.c -std=c11, the code compiles okay, but fails to run.
We get a message box saying the entry strtok_s could not be found in msvcrt.dll.

The reason which causes the problem is that, strtok_s is a newly added library function in ISO C11, thus any program using this function should be linked to msvcr90 at least. In reality, that program was linked to msvcrt 7.0 which was short of the function thus killed the program.

Operation System: Windows Server 2003
MSVCRT: 2005 SP1, 2010SP1, 2012(for XP, well it works on 2003 anyway)
MinGW-gcc: 4.8.1

Discussion

  • Earnie Boyd

    Earnie Boyd - 2013-08-19
    • status: unread --> open
    • assigned_to: Earnie Boyd
    • Type: Bug --> Support
    • Resolution: none --> invalid
    • Category: User_Error --> Waiting_User_Response
     
  • Earnie Boyd

    Earnie Boyd - 2013-08-19

    We do not even have the _s versions of the functions declared in our headers yet. That is planned for 5.0 release.

    We have not yet released gcc-4.8.1; I am working to get that done now.

    With these items, are you sure you have opened the ticket with the correct project?

    Also, it is the users responsibility to link to the correct versions of the libraries. Using a different runtime may cause you other headaches such as memory pointer clashing and memory leaks.

    The best advice is, if it isn't in MSVCRT.DLL then you shouldn't be using the function. Also, you need to decide which OS version is your minimum supported version, because MSVCRT.DLL is different on differing OS versions. That doesn't mean that all of the functions supported in the MSVCR##.DLL are supported in the MSVCRT.DLL of similar ##.

     
  • Keith Marshall

    Keith Marshall - 2013-08-19
    • Description has changed:

    Diff:

    --- old
    +++ new
    @@ -1,5 +1,6 @@
     The following C code results in a DLL initialization error:
    
    +~~~~
     #include <stdio.h>
     #define __STDC_WANT_LIB_EXT1__ 1
     #include <string.h>
    @@ -13,6 +14,7 @@
            p = strtok_s(0, ",", &ctx);
        }
     }
    +~~~~
    
     Compiled with gcc main.c -std=c11, the code compiles okay, but fails to run.
     We get a message box saying the entry strtok_s could not be found in msvcrt.dll.
    
     
  • Keith Marshall

    Keith Marshall - 2013-08-19

    [<sigh>I do wish users would mark up code samples appropriately</sigh>]

    The reason which causes the problem is that, strtok_s is a newly added library function in ISO C11, thus any program using this function should be linked to msvcr90 at least.

    This is an incorrect analysis. Certainly, as you are trying to use it, you appear to expect C11 semantics, but see, the real problem is that Microsoft's strtok_s, which they introduced long before the C11 variant was ever proposed, (and it is in plain old MSVCRT.DLL on my Win7 VM, but not on my WinXP-SP2 VM), is incompatible with C11 semantics.

    As Earnie has already pointed out, MinGW headers do not yet include support for strtok_s(). Even if they did, your code would still be broken, because it gratuitously assumes C11 semantics where MinGW would expect MSVC semantics. FTR, the differences are:--

    1. According to ISO/IEC TR 24731-1, C11 requires:
      #define __STDC_WANT_LIB_EXT1__ 1
      before including string.h; for MSVC semantics, this macro is irrelevant.

    2. The C11 prototype for strtok_s() is, (also according to ISO/IEC TR 24731-1):
      char *strtok_s(char * restrict s1,
      rsize_t * restrict s1max,
      const char * restrict s2,
      char ** restrict ptr);

    3. The (incompatible) MSVC prototype is:
      char *strtok_s(char *strToken,
      const char *strDelimit,
      char **context);

    Your code needs to address these semantic differences; it is your bug, when you presume to use any documentation source other than MSDN, when you are using MinGW, (and that it appears that you may be using an incompatible string.h, from a non-MinGW source).

     
  • Keith Marshall

    Keith Marshall - 2013-08-19

    Okay, reviewing your code sample again, (after marking it up correctly, to make it legible), I can see that you are coding according to the MSVC prototype, so:--

    1. Why confuse the issue, by referring to an incompatible C11 standard?

    2. It is still your issue to resolve, that you need to link the appropriate supporting non-free DLL, or otherwise require Win7 or later MSVCRT.DLL

    This isn't, strictly, a MinGW bug.

     
  • LIU Hao

    LIU Hao - 2013-08-20

    Thanks for your replies!

    @Boyd
    I'm not using the official binary releases of MinGW since I'm a fervid follower of new ISO standards. g++ 4.7.1 is not enough for me.

    @Marshall
    Linking to msvcr90 results in another dll initialization error(0x80000003), and linking to msvcr100 results in crashes(I'm still trying to find the reason):

    #include<string>
    
    void foo(){
        std::string my;
        my.reserve(1000);
    }
    
    int main(){
        foo();
        foo();
    }
    

    The above code compiles with g++ test.cpp -std=c++11 -static-libstdc++ -lmsvcr100, but crashes.

    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x7c94a22a in ntdll!DbgBreakPoint () from D:\Windows\system32\ntdll.dll
    (gdb) bt
    #0  0x7c94a22a in ntdll!DbgBreakPoint () from D:\Windows\system32\ntdll.dll
    #1  0x7c9ab559 in ntdll!RtlpNtMakeTemporaryKey ()
       from D:\Windows\system32\ntdll.dll
    #2  0x7c98a384 in ntdll!RtlIpv4StringToAddressExW ()
       from D:\Windows\system32\ntdll.dll
    #3  0x7c9ac9f6 in ntdll!RtlpNtMakeTemporaryKey ()
       from D:\Windows\system32\ntdll.dll
    #4  0x7c98567a in ntdll!RtlIpv4StringToAddressExW ()
       from D:\Windows\system32\ntdll.dll
    #5  0x7c96e448 in ntdll!RtlAbsoluteToSelfRelativeSD ()
       from D:\Windows\system32\ntdll.dll
    #6  0x77b8cef6 in msvcrt!free () from D:\Windows\system32\msvcrt.dll
    #7  0x003f0000 in ?? ()
    #8  0x00416cfe in std::string::reserve(unsigned int) ()
    #9  0x00416066 in std::string::append(unsigned int, char) [clone .part.24] ()
    #10 0x004166e9 in std::string::resize(unsigned int) ()
    #11 0x00401632 in foo() ()
    #12 0x0040166e in main ()
    

    Despite that, let's talk about the strtok_s function:

    The M$ version of strtok_s differs from that provided by ISO C11,
    1. if MinGW decided to support an ISO-compatible strtok_s, the wrongly-declared prototype should have been corrected and a corresponding definition should have been provided in libstdc, or
    2. if MinGW decided to support an ISO-incompatible but MSVC-compatible one, it should have been designed to link such programs to msvcr100(despite the crash) rather than msvcrt, or
    3. if MinGW decided to support neither, the function prototype should have been deleted.

    In any case, it is a bug.

     
  • LIU Hao

    LIU Hao - 2013-08-20

    ** If I compile with -lmsvcr100, the program crashes. **

    OllyDBG has clarified that the built exe imports malloc() from msvcr100.dll but free() from msvcrt.dll, which results in undefined behavior.

     
  • Keith Marshall

    Keith Marshall - 2013-08-20

    I'm not using the official binary releases of MinGW ...

    So, why do you presume to file a bug against our product? By your own admission, you are not using it, so this must be your bug.

    since I'm a fervid follower of new ISO standards.

    Then why are you using a Microsoft OS? Their "embrace and extend"[*] policy guarantees that you will never attain such nirvana.

    [*] Translation: adopt terminology from the standard, to promote a fake impression of compliance; this is the "embrace" bit. Modify the functionality, with particular emphasis on adoption of techniques covered by dubious patents, to introduce incompatibilities which will promote vendor lock-in; this is the "extend" bit.

    ... with g++ test.cpp -std=c++11 -static-libstdc++ -lmsvcr100
    ... crashes.

    Of course it crashes...

    OllyDBG has clarified that the built exe imports malloc() from msvcr100.dll but free() from msvcrt.dll

    ...because your usage is completely wrong! If you must use MSVCR100.DLL -- which MinGW.org does not support, because that DLL is not legitimately redistributable under the terms of any licence we will accept -- then you must replace MSVCRT.DLL with MSVCR100.DLL completely, in your build. Simply adding -lmsvcr100 to your compile arguments doesn't achieve that; see the footnotes (in comments) here, for examples of the correct way to do it.

    Earnie, since you've adopted this ticket, I'll leave it to you to close it out. THIS IS NOT A MINGW BUG.

     
    • Earnie Boyd

      Earnie Boyd - 2013-08-20

      I know it is not a MinGW bug that is why I changed it to a Support request. As for runtime versus compile time errors I tend to be a bit loose with which one is better. However, the 4.0 release introduces a new macro to help control the declarations and perhaps even apply inline code for the missing functions in other MSVCRT.DLL. But the inline code will not be a guarantee for all functions, the MSVCRT_VERSION macro will be used when XP doesn't contain the function but Win7 does, etc. The MSVCRT_VERSION value determines which OS the user intends to minimally support; it is assigned a value based on _WIN32_WINNT value and defaults to _WIN32_WINNT_WIN2K if _WIN32_WINNT is not set. I state all of that to say, when the MinGW headers contain the _s functions or any other function, they may not be present on a users OS but be present on the developers OS and therefore may be compile time or runtime error dependent on the situation. One user may run on Win7 without issue but another use running XP will experience a runtime error. This isn't something we can control.

      As for mixing and matching runtime environments, even Microsoft agrees that you cannot do that. You could load the alternate library to pick and choose the functions to use as long as you don't use functions that clash with memory and file handles.

       

      Last edit: Keith Marshall 2013-08-20
      • Keith Marshall

        Keith Marshall - 2013-08-20

        I know it is not a MinGW bug that is why I changed it to a Support request.

        I know that you knew this; the emphasis was more for the benefit of the OP, who reasserted the opposite, in spite of having been informed so already.

        FWIW, Microsoft's strtok_s() is actually (approximately) equivalent to POSIX's strtok_r(), (and incompatible with ISO-C11's strtok_s()). You may wish to bear this in mind, when you eventually get to adding *_s() prototypes -- e.g. you could consider adding a POSIX alias for strtok_r(), redirected via an inline function call, to MSVCRT.DLL's strtok_s().

        One user may run on Win7 without issue but another use running XP will experience a runtime error. This isn't something we can control.

        We can't control it, but we could handle it more gracefully at runtime, if we wrap the call in a GetProcAddress() helper; this could then return an error condition which the application could handle, rather than simply crashing, when the function is missing.

         
  • Earnie Boyd

    Earnie Boyd - 2013-08-20
    • labels: library bug -->
    • status: open --> closed
    • Category: Waiting_User_Response --> Invalid
     
  • Earnie Boyd

    Earnie Boyd - 2013-08-20

    I'm closing this since 1) it is not a MinGW issue and 2) there is another issue open to address all _s functions.

     
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.