tags:

views:

460

answers:

6

Hi,

using the Symbian S60 5th edition SDK released on October 2nd, I am compiling/running(on sim) the following code snippet:

void test(wchar_t *dest, int size, const wchar_t *fmt, ...) {
    va_list vl;
    va_start(vl, fmt);
    vswprintf(dest, size, fmt, vl);
    va_end(vl);
}

...

wchar_t str[1024];

// this crashes (2nd string 123 characters (+ \0) equals 248 bytes)
test(str, 1024, L"msg: %S", L"this is a test messagethis is a test messagethis is a test messagethis is a test messagethis is a test messagethis is a tes");

// this works (2nd string 122 characters (+ \0) equals 246 bytes)
test(str, 1024, L"msg: %S", L"this is a test messagethis is a test messagethis is a test messagethis is a test messagethis is a test messagethis is a te");

For no reason obvious to me (even after having read the vswprintf man page a hundred times) can I figure out why this code is crashing on me in the vswprintf call for long strings :-( The exact same code works fine on a Linux box. There is sufficient memory allocated for str, plus vswprintf is checking for buffer overruns anyway. Unfortunately the ... S60 debugger does not break on this crash, so I have no details :-(

Does anybody have any ideas?

Assuming a bug in Symbian's vswprintf routine, what would be possible replacement functions using POSIX compliant code? (this is supposed to be a cross-platform library)

Thanks.

A: 

Change the %S to a %s - uppercase to lowercase.

In MS-based printfs, %S means unicode characters, so this is why the 123 character string fails, it expects 2 bytes per character. (note %S is not part of the standard, so Symbian may be different here)

Actually, I think that still applies to Symbian.

gbjbaanb
No, he wants %S (which is equivalent to %ls) - the L prefix before the string constants makes them wide-character string constants.
Adam Rosenfield
Adam ist right, the standard says %s=char*, %S=wchar_t*. MS screwed this up by making %s be TCHAR and %S !TCHAR, hence the confusion. %S is actually correct here. Even if it weren't, it wouldn't cause a crash (just the string to be one character long only).
Steven
+1  A: 

To me this looks like a job for stepping into the vswprintf() call. Even if you can only do assembly-level debugging, it should be clear what's more or less going on by keeping a watch on what's going into the the str[] memory.

Michael Burr
A: 

You could try changing the %S format specifier to %ls. As mentioned in my earlier comment, they're supposed to be equivalent, but there could be a bug in the implementation. Note that the vswprintf function is defined in the C99 standard, and since there are not yet any fully conforming C99 compilers (I believe), it's very possible that any given implementation of vswprintf does not fully conform to the spec, or that it contains bugs (the former is more likely than the latter).

Adam Rosenfield
The Symbian docs (see link in question) actually mention %S. Nonetheless it's worth a try ... unfortunately it doesn't change the situation at all.
Steven
A: 

Can you try not calling test() and using swprintf instead -- in case the bug has to do with VARARGS handling?

Lou Franco
Using swprintf does not make a difference.
Steven
A: 

I've now "solved" this problem by using Symbian functions to perform this task:

void test(wchar_t *dest, int size, const wchar_t *fmt, ...) {
    VA_LIST args;
    VA_START(args, fmt);

    TPtrC16 fmtPtr((const TUint16*)fmt, wcslen(fmt) + 1);  
    TPtr16  targetPtr((TUint16*)dest, size);

    targetPtr.FormatList(fmtPtr, args);
    targetPtr.ZeroTerminate();

    VA_END(args);
}

(in which case you actually have to use %s)

Steven
A: 

I happened to find an internal buffer inside vswprintf's implementation to be hard-coded to 128 bytes (shucks!). This could very well cause such a crash on long strings.

Gerald Naveen