Я заметил (на мой взгляд) очень странное поведение snprintf с С++ на нескольких платформах. Рассмотрим следующий код (минимальный рабочий пример, который вызывает наблюдаемое поведение):
#include <stdio.h>
char test1[512];
char test2[512];
char test3[1024];
char test4[1024];
int main()
{
snprintf(test1, sizeof(test1), "test1");
snprintf(test2, sizeof(test2), "test2");
snprintf(test3, sizeof(test3), "%s %s", test1, test2);
return 0;
}
При запуске, хотя valgrind с --tool = exp-sgcheck, сообщается о следующей ошибке (для третьего оператора snprintf):
==30302== Invalid read of size 1
==30302== at 0x568E4EB: vfprintf (in /lib64/libc-2.19.so)
==30302== by 0x56B7608: vsnprintf (in /lib64/libc-2.19.so)
==30302== by 0x5695209: snprintf (in /lib64/libc-2.19.so)
==30302== by 0x4006AD: main (1.cc:12)
==30302== Address 0x601460 expected vs actual:
==30302== Expected: global array "test1" of size 1,024 in object with soname "NONE"
==30302== Actual: global array "test2" of size 512 in object with soname "NONE"
==30302== Actual: is 0 after Expected
Таким образом, передача test1 в качестве аргумента для первого% s приводит к чтению после конца массива test1.
Такое поведение вызвало несколько ошибок страниц в драйвере Windows (да, я знаю, это статические данные...). К счастью, код переносимый, и при портировании в linux valgrind сообщалось об этой ошибке.
Но, насколько мне известно, snprintf должен заканчивать test1 с \0 на 6-м байте (что он делает, проверял это). Так почему же 3-й оператор snprintf читает после конца массива test1? Изменение 3-й инструкции snprintf на
snprintf(test3, sizeof(test3), "%.512s %s", test1, test2);
решает проблему на обеих платформах. Компиляция кода как кода C (не С++) не приводит к ошибке.
UPDATE: в Linux (и, возможно, в окнах) ошибка возникает только в том случае, если код скомпилирован с включенной отладочной информацией и отключен оптимизация (-g -O0 для gcc).