Это просто ошибка в vprintf_l
, которая обрабатывает printf
(и, вероятно, всех его друзей).
Строго говоря, библиотека имеет право справиться с этой ситуацией, делая все, что угодно, включая повреждение кучи, но, судя по коду, намерение - как и должно быть для любой не-мусорной реализации printf
- - это разумно обращаться с NULL
строками. В коде просто есть ошибка, которая делает это. Эти вещи случаются.
Если предпринята попытка напечатать указатель на символ шириной NULL
после того, как был напечатан предыдущий указатель на символ шириной не NULL
, vprintf_l
подхватит следующий строковый аргумент или при выходе из vprintf_l
. (Возможно, есть и другие способы, чтобы это произошло - я не проверял.)
Код ошибки здесь:
case 's':
if (flags & LONGINT) {
wchar_t *wcp;
if (convbuf != NULL)
free(convbuf);
if ((wcp = GETARG(wchar_t *)) == NULL)
cp = "(null)";
else {
convbuf = __wcsconv(wcp, prec, loc);
if (convbuf == NULL) {
fp->_flags |= __SERR;
goto error;
}
cp = convbuf;
}
} else if ((cp = GETARG(char *)) == NULL)
Если GETARG(wchar_t *)
возвращает NULL
, convbuf
будет указывать на старый (и теперь освобожденный) буфер. Затем при выходе из функции происходит двойное освобождение:
if (convbuf != NULL)
free(convbuf);
То же самое применимо, если бы был другой строковый аргумент, хотя в этом случае двойное освобождение происходит в приведенном выше коде case 's'
:
printf("a=%ls, b=%ls c=%ls\n", L"a", b, L"c");
Конечно, решением было бы установить convbuf
на NULL
после освобождения.
Код printf
здесь:
http://www.opensource.apple.com/source/Libc/Libc-594.1.4/stdio/vfprintf-fbsd.c
Судя по разборке, это код, который используется для среды выполнения по умолчанию в Snow Leopard.