Я наблюдаю интересную проблему с реализацией Microsoft strncat
. Он касается 1 байта за пределами исходного буфера. Рассмотрим следующий код:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
void main()
{
char dstBuf[1024];
char* src = malloc(112);
memset(src, 'a', 112);
dstBuf[0] = 0;
strncat(dstBuf, src, 112);
}
strncat
читает 1 байт после 112-байтового блока. Поэтому, если вам не повезло получить выделение на недопустимой границе страницы, ваше приложение вылетит. Большие приложения могут периодически давать сбой в таких местах. (Обратите внимание, что такое состояние можно смоделировать с помощью параметра gflags PageHeap; размер блока должен быть кратен размеру указателя для правильного выравнивания.)
Это ожидаемое поведение или ошибка? Есть ссылки подтверждающие это? (Я читал несколько описаний strncat
, но их можно интерпретировать двояко, в зависимости от вашего первоначального настроя...)
Обновление (для ответов на вопросы о доказательствах): прошу прощения, если из текста выше не понятно, но это экспериментальный факт. Я наблюдаю периодические сбои в приложении по адресу strncat
чтения src+srcBufSize. В этом небольшом примере запуск с gflags PageHeap при сбое воспроизводится стабильно (100%). Так что, насколько я вижу, доказательства очень веские.
Update2 (информация о компиляторе) MS Visual Studio 2005, версия 8.0.50727.867. Платформа сборки: 64-битная версия (без воспроизведения для 32-битной версии). ОС, использованная для воспроизведения сбоя: Windows Server 2008 R2.
Обновление 3 Проблема также воспроизводится с двоичным файлом, встроенным в MS Visual Studio 2012 11.0.50727.1.
Обновление 4 Ссылка на выпуск в Microsoft Connect; ссылка на обсуждение на форумах MSDN
Обновление 5. Проблема будет исправлена в следующем выпуске VS. Исправление для старых версий не планируется. См. ссылку «Microsoft Connect» выше.
src
указывает на массив указателей, не заканчивающийся NUL, размер которого кратен 8, отличному от 0, читается двойное слово сразу за массивом, хотя прочитанное значение не используется.mov (%rdx),%rax; sub $0x8,%r8; jb 0x400011a7
← Я могу придумать пару способов изменить это за счет производительности. - person ninjalj   schedule 06.09.2013jb
наjbe
работает, но тогда окончательная копия qword делается байт за байтом. Что касается 32-битной версии, то хотя она и основана на той же идее, детали немного отличаются. В частности, цикл конкатенации выровненного [qd]слова использует счетчик двойных слов и завершается на нуле в 32-разрядной версии, тогда как в 64-разрядной версии используется счетчик байтов, и он завершается при значении ниже нуля (как я сказал, что он мог быть ниже или равен нулю, 64-битная версия имеет резервный код до 8 последних байтов). - person ninjalj   schedule 09.09.2013mov (%rdx),%rax
послеjb 0x400011a7
также работает, но некоторые из следующих инструкций зависят от%rax
, что может привести к снижению производительности. Резюмируя, я согласен, что это ошибка. - person ninjalj   schedule 09.09.2013