Greg Ercolano wrote:
>    ..and complete build output just to show how it worked (and what
>    warning messages were left) over here:
> 
>       BUILD LOG:
>       
> http://seriss.com/people/erco/fltk/tmp/okbuild-6971-win32-vsexpress-2008.txt

    Just a reminder; the warnings from the WIN32 build about snprintf() being 
unsafe
    in the above are true; the /WINDOWS/ implementation of snprintf() is bad, 
it does
    not work the way the gnu snprintf() does ['correctly']. (See their docs for 
why)

    There is no easy solution to this, as the 'new' function Microsoft 
recommends,
    _snprintf_s(), does /not/ have the same calling parameters, so you can't 
just
    trivially change _snprintf() -> _snprintf_s().

    Here's some details from an email I sent someone while testing the boundary
    conditions of Microsoft's snprintf() under win32 vs linux, and was shocked
    at the different results:

* * *

    [..]it seems [the Microsoft] _snprintf() doesn't follow the C99 spec,
    so the function apparently works incorrectly on the very
    boundary conditions it's supposed to protect us from. eg:

#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#define snprintf _snprintf
#define strcpy strcpy_s
#endif /*MICROSOFT*/
int main() {
    int ret;
    char ss[20];
    strcpy(ss, "********XY");           // 'X' and 'Y' should never be touched 
or seen
    ret=snprintf(ss, 8, "1234%s","56");     fprintf(stderr,"[OK]  RET=%d, 
SS='%s' X OK? %s\n", ret, ss, ss[8]=='X'?"yes":"NO!");
    ret=snprintf(ss, 8, "1234%s","567");    fprintf(stderr,"[OK]  RET=%d, 
SS='%s' X OK? %s\n", ret, ss, ss[8]=='X'?"yes":"NO!");
    ret=snprintf(ss, 8, "1234%s","5678");   fprintf(stderr,"[BAD] RET=%d, 
SS='%s' X OK? %s\n", ret, ss, ss[8]=='X'?"yes":"NO!");
    ret=snprintf(ss, 8, "1234%s","56789");  fprintf(stderr,"[BAD] RET=%d, 
SS='%s' X OK? %s\n", ret, ss, ss[8]=='X'?"yes":"NO!");
    ret=snprintf(ss, 8, "1234%s","567890"); fprintf(stderr,"[BAD] RET=%d, 
SS='%s' X OK? %s\n", ret, ss, ss[8]=='X'?"yes":"NO!");
}

    ..under linux, the correct output is given:

[OK]  RET=6, SS='123456' X OK? yes
[OK]  RET=7, SS='1234567' X OK? yes
[BAD] RET=8, SS='1234567' X OK? yes
[BAD] RET=9, SS='1234567' X OK? yes
[BAD] RET=10, SS='1234567' X OK? yes

    ..when the boundary limit is reached, the string remains null terminated.

    BUT under windows it leaves the string unterminated (apparently as 
documented!),
    as the "XY" shown in the following output makes clear:

[OK]  RET=6, SS='123456' X OK? yes
[OK]  RET=7, SS='1234567' X OK? yes
[BAD] RET=8, SS='12345678XY' X OK? yes    <-- argh -- XY should not show up.
[BAD] RET=-1, SS='12345678XY' X OK? yes   <-- argh
[BAD] RET=-1, SS='12345678XY' X OK? yes   <-- argh

    Their docs do recommend using _snprintf_s() instead of _snprintf(),
    which is supposedly their 'secure' version of _snprintf().

    Well, I tried that, but then the above program /crashes/..!
    Reading the docs, I can think of no reason why it should crash.
    Apparently their 'secure' function is worse than the insecure one.

    [..]Seems the "right" solution is as follows, I'm not sure I see
    a "macro" way to hide this, since the argument list is different
    and this is a "varargs" type function:

#ifdef _WIN32
    _snprintf_s(nametmp, sizeof(nametmp), _TRUNCATE, "%s_%d", name.c_str(), 
id);        // microsoft's _sprintf() doesn't truncate(!) use _sprintf_s() 
instead
#else
    snprintf(nametmp, sizeof(nametmp), "%s_%d", name.c_str(), id);
#endif

    That extra "_TRUNCATE" argument before the format string being the
    issue that seems to prevent using a macro to hide this.
_______________________________________________
fltk-dev mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-dev

Reply via email to