Анализатор обнаружил потенциальную ошибку, связанную с несовместимостью данных, которыми обменивается 32-битная и 64-битная версия программы. В поток записываются или из потока читаются переменные memsize-типа. Ошибка может заключаться в том, что данные записанные в бинарный файл в 32-х битном приложении будут некорректно прочитаны 64-х битном приложением.
Рассмотрим пример такого кода:
std::vector<int> v;
....
ofstream os("myproject.dat", ios::binary);
....
os << v.size();
Функция 'size()' возвращает значение с типом size_t. Его размер различен в 32-х и 64-х битных приложениях. Соответственно, в файл будет записано различное количество байт.
Способов избежать несовместимости данных достаточно много. Самый простой и грубый способ, это жестко задать размер читаемых и записываемых типов. Пример такого кода:
std::vector<int> v;
....
ofstream os("myproject.dat", ios::binary);
....
os << static_cast<__int64>(v.size());
Естественно, жёсткий переход на 64-битные типы данных нельзя назвать хорошим решением. Например, этот способ не позволит читать данные, записанные старой 32-битной программой. Если читать и записывать данные как 32-битные значения, возникнет другая проблема. В этом случае, 64-битная программа не сможет записать информацию о массивах, состоящих более чем из 2^32 элементов. Это может быть неприятным ограничением. Ведь часто 64-битные программы создаются именно для того, чтобы работать с огромными массивами данных.
Выходом из этой ситуации может стать внесения понятия версии сохраненных данных. Например, 32-битная программа сможет открывать файлы, созданные только 32-битной версией. А 64-битная программа будет работать с данными, сгенерированными как 32-битной, так и 64-битной версией программы.
Ещё один вариант решения проблемы совместимости данных это хранение их в текстовом виде, или использовании XML формата данных.
Следует отметить, что далеко не во всех программах имеет место проблема совместимости данных. Если программа не создает проекты и иные файлы, которые нужно открывать на других компьютерах, то диагностику V128 можно просто отключить.
Также, нет смысла беспокоиться, если поток используется для распечатки значений на экране. PVS-Studio, по возможности, пытается определить такие ситуации и не выдавать сообщения. Однако, появление ложных сообщений весьма вероятно. В этом случае, вы можете воспользоваться одним из механизмов подавления ложных предупреждений, описанных в документации.
Дополнительные возможности
По просьбе пользователей реализована возможность самостоятельно указать, какие из функций используются для сохранения/чтения данных. Если в эти функции передаются memsize-типы, то это считается опасным кодом.
Формат расширения следующий: возле прототипа функции (или возле её реализации, или в общем заголовочном файле) пишется комментарий специального вида. Начнём с примера использования:
//+V128, function:write, non_memsize:2
void write(string name, char);
void write(string name, int32);
void write(string name, int64);
foo()
{
write("zz", array.size()); // warning V128
}
Формат:
Уровень диагностики в случае срабатывания на пользовательской функции – всегда первый.
Напоследок дадим наиболее полный пример использования:
// Предупреждать, когда в метод C класса B
// из пространства имён A во второй или третий
// аргумент была помещена переменная типа memsize:
//+V128,namespace:A,class:B,function:C,non_memsize:3,non_memsize:2