DO NOT REPLY TO THIS MESSAGE.  INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.

[STR New]

Link: http://www.fltk.org/str.php?L2306
Version: 1.3-current


The following is a redux of the thread on fltk.development:
"Subject: snprintf() warnings under win32"

snprintf() is supposed to protect against overruns, but the behavior
varies across platforms due to some problem/disagreement in the C
standards. In short, depending on the platform, on a potential overrun,
the resulting string can be left /without/ a NULL termination, which is
often unexpected.

1) The GNU snprintf() does what one expects; on an overrun, leaves a NULL
terminated string behind.

2) The VS snprintf() leaves an UN-TERMINATED string behind on an overrun.
Some other compilers do this too. The microsoft compiler warns about use
of this function, and we should heed it. Their docs recommend the use of
_snprintf_s(), which has slightly different calling semantics than normal
snprintf(), so a "simple" macro redefinition won't solve it.

What has been suggested:

    a) Create a "complex" C99 compliant macro redefinition for VS builds:
       #ifdef WIN32   // might need to be more VS specific
       #define SNPRINTF(SS, CC, ...) _snprintf_s(SS, CC, _TRUNCATE,
__VA_ARGS__)
       #else
       #define SNPRINTF snprintf      // or some such
       #endif

    b)  Have FLTK use its own built-in fl_snprintf() code,
        which works on all platforms because the function is
        implemented completely as code (ie. is /not/ a wrapper function)

I'd definitely lean on the side of (b), since /for sure/ that will work
consistently regardless of the platform.

However, fl_snprintf() does need some docs; it's unclear what it
guarantees in the way of the returned string, and which format characters
it supports. Empirical evidence shows it acts similarly to the GNU
snprintf(); on overrun, leaves a terminated string.

Also: fl_snprintf() is only accessible to FLTK source code; the #include
needed is flstring.h, which lives in the src dir, and NOT the "FL" dir. It
might be handy to have this be a public global, and have it fully
doxygen'ed. 

Finally, fl_snprintf() needs to cite the source for the implemented code.
If taken from GNU, we should know which version so potential bugs can be
tracked. Or if one of our guys wrote it, who?

Attached "erco-snprintf-test.cxx" demonstrates if the local snprintf()
function leaves an unterminated string or not. 

        Output on Linux:

RET=6, SS='123456': TEST RESULT: OK
RET=7, SS='1234567': TEST RESULT: OK
RET=8, SS='1234567': TEST RESULT: OK
               ^^ remains truncated even though input len >= 8
RET=9, SS='1234567': TEST RESULT: OK
RET=10, SS='1234567': TEST RESULT: OK

        Output on Win32:

RET=6, SS='123456': TEST RESULT: OK
RET=7, SS='1234567': TEST RESULT: OK
RET=8, SS='12345678XY': TEST RESULT: FAIL!
               ^^ Yikes -- unterminated; the 'XY' shouldn't show up
RET=-1, SS='12345678XY': TEST RESULT: FAIL!
RET=-1, SS='12345678XY': TEST RESULT: FAIL!


Link: http://www.fltk.org/str.php?L2306
Version: 1.3-current
#include <stdio.h>
#include <string.h>
// Verify that snprintf() returns a NULL terminated string on overrun 
conditions. erco 12/30/09
#ifdef _WIN32
#define snprintf _snprintf      // microsoft 'deprecated' this function, so 
must have leading '_'
#endif /*MICROSOFT*/
int main() {
    int ret;
    char ss[20];
    strcpy(ss, "12345678XY");   // 'X' and 'Y' should never be touched or seen 
in the following
    ret=snprintf(ss, 8, "1234%s","56");     fprintf(stderr,"RET=%d, SS='%s': 
TEST RESULT: %s\n", ret, ss, 
(ss[8]=='X'&&ss[9]=='Y'&&strlen(ss)<8)?"OK":"FAIL!");
    ret=snprintf(ss, 8, "1234%s","567");    fprintf(stderr,"RET=%d, SS='%s': 
TEST RESULT: %s\n", ret, ss, 
(ss[8]=='X'&&ss[9]=='Y'&&strlen(ss)<8)?"OK":"FAIL!");
    ret=snprintf(ss, 8, "1234%s","5678");   fprintf(stderr,"RET=%d, SS='%s': 
TEST RESULT: %s\n", ret, ss, 
(ss[8]=='X'&&ss[9]=='Y'&&strlen(ss)<8)?"OK":"FAIL!");
    ret=snprintf(ss, 8, "1234%s","56789");  fprintf(stderr,"RET=%d, SS='%s': 
TEST RESULT: %s\n", ret, ss, 
(ss[8]=='X'&&ss[9]=='Y'&&strlen(ss)<8)?"OK":"FAIL!");
    ret=snprintf(ss, 8, "1234%s","567890"); fprintf(stderr,"RET=%d, SS='%s': 
TEST RESULT: %s\n", ret, ss, 
(ss[8]=='X'&&ss[9]=='Y'&&strlen(ss)<8)?"OK":"FAIL!");
    return(0);
}
_______________________________________________
fltk-bugs mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-bugs

Reply via email to