SlideShare a Scribd company logo
Паттерны 64-битных
ошибок в играх
Андрей Карпов
karpov@viva64.com
Докладчик
• Карпов Андрей Николаевич
• На Хабр: habr.com/users/Andrey2008/
• Microsoft MVP, Intel Black Belt Software Developer
• Один из основателей проекта PVS-Studio, который
как раз начинался с поиска 64-битных ошибок
• https://www.viva64.com
Формально «64-битных ошибок» нет
Практика
• 64-битные ошибки – это ошибки, которые начинают проявлять
себя после сборки 64-битного приложения
• Причём многие только когда пересекается граница 4 Гигабайта
Пояснение на примере malloc
• Кто увидит ошибку?
void Foo()
{
const size_t Gigabyte = 1073741824;
void *A[10];
for (size_t i = 0; i < 10; ++i)
{
A[i] = malloc(Gigabyte);
printf("%pn", A[i]);
}
for (size_t i = 0; i < 10; ++i)
free(A[i]);
}
В C-коде забывают подключать
заголовочные файлы
• В вашей программе может не быть вызовов malloc, но они могут
быть в сторонних библиотеках
• Проявляется только при потреблении большого объема памяти
#include <stdio.h>
#include <string.h>
//#include <stdlib.h>
И дело не только в malloc
• Fennec Media
• memset
• memcpy
• Ffdshow (media decoder)
• memset
• memcpy
• libZPlay
• strlen
Продолжим про неявное
усечение 64-битных значений
Тип long в Win64
const std::vector<Vec2> &vertexList =
body->getCalculatedVertexList();
unsigned long length = vertexList.size();
PVS-Studio: V103 Implicit type conversion from memsize to 32-bit type.
CCArmature.cpp 614
Cocos2d-x
Тип int – плохая идея в любом случае
PVS-Studio: V104 Implicit conversion of 'i' to memsize type in an arithmetic
expression: i < points_.size() sweep_context.cc 76
std::vector<Point*> points_;
void SweepContext::InitTriangulation()
{
// Calculate bounds.
for (unsigned int i = 0; i < points_.size(); i++) {
Point& p = *points_[i];
....
Cocos2d-x
Кстати, такие ошибки намного коварнее,
чем кажутся
• При переполнении int возникает неопределённое поведение
• UB – это, в том числе, когда всё работает правильно :)
• Подробности: "Undefined behavior ближе, чем вы думаете"
https://www.viva64.com/ru/b/0374/
size_t N = foo();
for (int i = 0; i < N; ++i)
Использование правильных
memsize-типов
"memsize" типы
• ptrdiff_t - знаковый тип (дистанция между указателями)
• size_t - максимальный размер теоретически возможного объекта
любого типа, включая массивы
• rsize_t - размер одиночного объекта
• intptr_t - знаковый тип, может хранить указатель
• uintptr_t - беззнаковый тип, может хранить указатель
Использование memsize-типов
• Количество элементов в массиве
• Размер буфера
• Счётчики
• Хранение указателя (хотя так лучше не делать)
• Адресная арифметика
• и так далее
Использование memsize-типов: плохо
PVS-Studio: V109 Implicit type conversion of return value 'a * b * c' to memsize
type. test.cpp 22
Потенциальное переполнение
size_t Foo(int a, int b, int c)
{
return a * b * c;
}
Использование memsize-типов: OK
size_t Foo(int a, int b, int c)
{
return static_cast<size_t>(a)
* static_cast<size_t>(b)
* static_cast<size_t>(c);
}
size_t Foo(int a, int b, int c)
{
return static_cast<size_t>(a) * b * c;
}
ТОЛЬКО НЕ ДЕЛАЙТЕ ТАК!
std::vector<unsigned char> buf(
static_cast<size_t>(exr_image->width * h * pixel_data_size));
PVS-Studio: V1028 CWE-190 Possible overflow. Consider casting operands, not the
result. tinyexr.h 11682
Вновь потенциальное
переполнение
TinyEXR
Так ошибки только больше маскируются
if (components == 1) {
images[0].resize(static_cast<size_t>(width * height));
memcpy(images[0].data(), data, sizeof(float) * size_t(width * height));
} else {
images[0].resize(static_cast<size_t>(width * height));
images[1].resize(static_cast<size_t>(width * height));
images[2].resize(static_cast<size_t>(width * height));
images[3].resize(static_cast<size_t>(width * height));
for (size_t i = 0; i < static_cast<size_t>(width * height); i++) {
TinyEXR
Ещё про адресную арифметику
int A = -2;
unsigned B = 1;
int array[5] = { 1, 2, 3, 4, 5 };
int *ptr = array + 3;
ptr = ptr + (A + B);
printf("%in", *ptr); //Access violation
//on 64-bit platform
Забывают расширить 32-битные
типы
int64_t X = 1 << N
• Этот код не работает и в 32-битных программах
• Но там обычно и не понадобится выставлять старшие биты
class FMallocBinned : public FMalloc
{
uint64 PoolMask;
....
FMallocBinned(uint32 InPageSize, uint64 AddressLimit)
{
....
PoolMask = (( 1 << ( HashKeyShift - PoolBitShift ) ) - 1);
....
}
};
Unreal Engine 4
PVS-Studio: V629 Consider inspecting the '1 << (HashKeyShift - PoolBitShift)'
expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-
bit type. mallocbinned.h 800
class FMallocBinned : public FMalloc
{
uint64 PoolMask;
....
FMallocBinned(uint32 InPageSize, uint64 AddressLimit)
{
....
PoolMask = (( 1ULL << ( HashKeyShift - PoolBitShift ) ) - 1);
....
}
};
Unreal Engine 4
Godot Engine
void vp9_adjust_mask(....) {
....
const uint64_t columns = cm->mi_cols - mi_col;
const uint64_t mask_y =
(((1 << columns) - 1)) * 0x0101010101010101ULL;
....
}
PVS-Studio: V629 CWE-190 Consider inspecting the '1 << columns'
expression. Bit shifting of the 32-bit value with a subsequent expansion to
the 64-bit type. vp9_loopfilter.c 851
size_t N = ~0U;
• В 32-битном коде всё OK
• 64-битный код, ожидание: 0xFFFFFFFFFFFFFFFF
• 64-битный код, реальность: 0x00000000FFFFFFFF
size_t nRenderMeshSize = ~0U;
PVS-Studio: V101 Implicit assignment type conversion to memsize type.
StatObjLoad.cpp 1369
CryEngine
size_t N = ~(1024u - 1);
• В 32-битном коде всё OK
• 64-битный код, ожидание: 0xFFFFFFFFFFFFFC00
• 64-битный код, реальность: 0x00000000FFFFFC00
static const UINT_PTR SmallBlockAlignMask = ~(SmallBlockLength - 1);
FreeBlockHeader* InsertFreeBlock(FreeBlockHeader* after,
UINT_PTR start, UINT_PTR end)
{
bool isFreeBlockDone = (start & SmallBlockAlignMask) ==
(end & SmallBlockAlignMask) ||
(start > end - (SmallBlockLength / 2));
....
}
CryEngine
Увеличенное потребление
стека и динамической памяти
Стек
• Предлагаю не думать и просто увеличить его в 2 раза :)
Динамическая память
• Есть смысл повоевать
• Везде ли нужны 64-битные целочисленные типы?
• Везде ли нужны указатели?
• Размер структур
Избыточный рост размера структур
struct Candidate {
uint32_t face;
ChartBuildData *chart;
float metric;
};
PVS-Studio: V802 On 64-bit platform, structure size can be reduced from 24 to 16
bytes by rearranging the fields according to their sizes in decreasing order. xatlas.cpp
5237
24 байта
Избыточный рост размера структур
struct Candidate {
ChartBuildData *chart;
uint32_t face;
float metric;
};
16 байт
Прочие паттерны ошибок
Магические константы
• 1024 x 768
• 1600 x 1200
Магические константы
• 1024 x 768
• 1600 x 1200
• 4
• 32
• 0x7FFFFFFF
• 0x80000000
• 0xFFFFFFFF
Опасные трюки с приведением типов
ResourceBase::Header *header = (*iter).value;
char fourCC[ 5 ];
*( ( U32* ) fourCC ) = header->getSignature();
fourCC[ 4 ] = 0;
Здесь из-за header всё будет хорошо, но всё это очень нестабильно.
PVS-Studio: V1032 The pointer 'fourCC' is cast to a more strictly aligned pointer
type. resourceManager.cpp 127
Torque 3D
Сериализация данных
• Нет конкретных ошибок и советов
• Сделайте Code-Review
Массивы разных типов
Виртуальные функции
Виртуальные функции
Как написать качественную
64-битную программу?
Уточнить стандарт кодирования
• Использовать правильные типы:
ptrdiff_t, size_t, intptr_t, uintptr_t, INT_PTR, DWORD_PTR и т.д.
• Нет магическим числам. Использовать:
UINT_MAX, ULONG_MAX, std::numeric_limits<size_t>::max() и т.д.
• Объяснить, как правильно пользоваться явным приведением
типов в выражениях, и чем 1 отличается от static_cast<size_t>(1)
• unsigned long != size_t
Инструментарий: юнит-тесты
Инструментарий: динамические анализаторы
Инструментарий: статические анализаторы
Заключение
• Даже если вы уже выпустили 64-битное приложение, это не
значит, что оно работает
• 64-битная ошибка может выжидать годами
• Как улучшить ситуацию:
• обучение
• стандарт кодирования
• статический анализ кода
Полезные ссылки
• Уроки разработки 64-битных приложений на языке Си/Си++
https://www.viva64.com/ru/l/full/
• Коллекция примеров 64-битных ошибок в реальных программах
https://www.viva64.com/ru/a/0065/
• Undefined behavior ближе, чем вы думаете
https://www.viva64.com/ru/b/0374/
Ответы на вопросы
Андрей Карпов
karpov@viva64.com
www.viva64.com

More Related Content

What's hot

Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кода
Sergey Platonov
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
OOO "Program Verification Systems"
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
Mikhail Kurnosov
 
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
corehard_by
 
Когда в C# не хватает C++ . Часть 3.
Когда в C# не хватает C++. Часть 3. Когда в C# не хватает C++. Часть 3.
Когда в C# не хватает C++ . Часть 3.
Mikhail Shcherbakov
 
Когда в C# не хватает C++ . Часть 2.
Когда в C# не хватает C++. Часть 2.Когда в C# не хватает C++. Часть 2.
Когда в C# не хватает C++ . Часть 2.
Mikhail Shcherbakov
 
Когда в C# не хватает C++
Когда в C# не хватает C++Когда в C# не хватает C++
Когда в C# не хватает C++
Mikhail Shcherbakov
 
Разбор алгоритмов генерации псевдослучайных чисел / Андрей Боронников (IT Ter...
Разбор алгоритмов генерации псевдослучайных чисел / Андрей Боронников (IT Ter...Разбор алгоритмов генерации псевдослучайных чисел / Андрей Боронников (IT Ter...
Разбор алгоритмов генерации псевдослучайных чисел / Андрей Боронников (IT Ter...
DevGAMM Conference
 
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
 Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ... Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
Yandex
 
хитрости выведения типов
хитрости выведения типовхитрости выведения типов
хитрости выведения типов
corehard_by
 
Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)
Mikhail Kurnosov
 
Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!
RAMBLER&Co
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
Andrey Karpov
 
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...Ontico
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMP
Mikhail Kurnosov
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Yandex
 
Модель памяти C++ - Андрей Янковский, Яндекс
Модель памяти C++ - Андрей Янковский, ЯндексМодель памяти C++ - Андрей Янковский, Яндекс
Модель памяти C++ - Андрей Янковский, Яндекс
Yandex
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
corehard_by
 
Построение компилятора на базе LLVM — Павел Сычев
 Построение компилятора на базе LLVM — Павел Сычев Построение компилятора на базе LLVM — Павел Сычев
Построение компилятора на базе LLVM — Павел Сычев
Yandex
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибки
Tatyanazaxarova
 

What's hot (20)

Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кода
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
 
Когда в C# не хватает C++ . Часть 3.
Когда в C# не хватает C++. Часть 3. Когда в C# не хватает C++. Часть 3.
Когда в C# не хватает C++ . Часть 3.
 
Когда в C# не хватает C++ . Часть 2.
Когда в C# не хватает C++. Часть 2.Когда в C# не хватает C++. Часть 2.
Когда в C# не хватает C++ . Часть 2.
 
Когда в C# не хватает C++
Когда в C# не хватает C++Когда в C# не хватает C++
Когда в C# не хватает C++
 
Разбор алгоритмов генерации псевдослучайных чисел / Андрей Боронников (IT Ter...
Разбор алгоритмов генерации псевдослучайных чисел / Андрей Боронников (IT Ter...Разбор алгоритмов генерации псевдослучайных чисел / Андрей Боронников (IT Ter...
Разбор алгоритмов генерации псевдослучайных чисел / Андрей Боронников (IT Ter...
 
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
 Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ... Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
 
хитрости выведения типов
хитрости выведения типовхитрости выведения типов
хитрости выведения типов
 
Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)
 
Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
 
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMP
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
Модель памяти C++ - Андрей Янковский, Яндекс
Модель памяти C++ - Андрей Янковский, ЯндексМодель памяти C++ - Андрей Янковский, Яндекс
Модель памяти C++ - Андрей Янковский, Яндекс
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
 
Построение компилятора на базе LLVM — Павел Сычев
 Построение компилятора на базе LLVM — Павел Сычев Построение компилятора на базе LLVM — Павел Сычев
Построение компилятора на базе LLVM — Павел Сычев
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибки
 

Similar to Паттерны 64-битных ошибок в играх

200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя:опыт статического анализа исходного кода200 open source проектов спустя:опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
Positive Hack Days
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
Tatyanazaxarova
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибки
Platonov Sergey
 
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Andrey Karpov
 
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryИнтервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Tatyanazaxarova
 
Как команда PVS-Studio может улучшить код операционной системы Tizen
Как команда PVS-Studio может улучшить код операционной системы TizenКак команда PVS-Studio может улучшить код операционной системы Tizen
Как команда PVS-Studio может улучшить код операционной системы Tizen
Andrey Karpov
 
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кодаСравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Tatyanazaxarova
 
Static code analysis of the projects built on Unreal Engine
Static code analysis of the projects built on Unreal EngineStatic code analysis of the projects built on Unreal Engine
Static code analysis of the projects built on Unreal Engine
DevGAMM Conference
 
Статический анализ кода проектов, построенных на движке Unreal Engine
Статический анализ кода проектов, построенных на движке Unreal EngineСтатический анализ кода проектов, построенных на движке Unreal Engine
Статический анализ кода проектов, построенных на движке Unreal Engine
Andrey Karpov
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Sergey Platonov
 
Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1
m2rus
 
Step cpp0201
Step cpp0201Step cpp0201
Step cpp0201
Evgenij Laktionov
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
Andrey Karpov
 
Современный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтерыСовременный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтеры
corehard_by
 
паскаль 10кл 14
паскаль 10кл 14паскаль 10кл 14
паскаль 10кл 14
Ирина Куликова
 
Особенности разработки 64-битных приложений
Особенности разработки 64-битных приложенийОсобенности разработки 64-битных приложений
Особенности разработки 64-битных приложений
Tatyanazaxarova
 
Изучение проблемы: перенос Си++ библиотек для работы с облаками точек итрианг...
Изучение проблемы: перенос Си++ библиотек для работы с облаками точек итрианг...Изучение проблемы: перенос Си++ библиотек для работы с облаками точек итрианг...
Изучение проблемы: перенос Си++ библиотек для работы с облаками точек итрианг...
Tatyanazaxarova
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числа
Tatyanazaxarova
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
Pavel Tsukanov
 

Similar to Паттерны 64-битных ошибок в играх (20)

200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя:опыт статического анализа исходного кода200 open source проектов спустя:опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибки
 
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
 
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryИнтервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
 
Как команда PVS-Studio может улучшить код операционной системы Tizen
Как команда PVS-Studio может улучшить код операционной системы TizenКак команда PVS-Studio может улучшить код операционной системы Tizen
Как команда PVS-Studio может улучшить код операционной системы Tizen
 
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кодаСравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
 
Static code analysis of the projects built on Unreal Engine
Static code analysis of the projects built on Unreal EngineStatic code analysis of the projects built on Unreal Engine
Static code analysis of the projects built on Unreal Engine
 
Статический анализ кода проектов, построенных на движке Unreal Engine
Статический анализ кода проектов, построенных на движке Unreal EngineСтатический анализ кода проектов, построенных на движке Unreal Engine
Статический анализ кода проектов, построенных на движке Unreal Engine
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
 
Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1
 
Step cpp0201
Step cpp0201Step cpp0201
Step cpp0201
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
 
Современный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтерыСовременный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтеры
 
паскаль 10кл 14
паскаль 10кл 14паскаль 10кл 14
паскаль 10кл 14
 
Особенности разработки 64-битных приложений
Особенности разработки 64-битных приложенийОсобенности разработки 64-битных приложений
Особенности разработки 64-битных приложений
 
Изучение проблемы: перенос Си++ библиотек для работы с облаками точек итрианг...
Изучение проблемы: перенос Си++ библиотек для работы с облаками точек итрианг...Изучение проблемы: перенос Си++ библиотек для работы с облаками точек итрианг...
Изучение проблемы: перенос Си++ библиотек для работы с облаками точек итрианг...
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числа
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 

More from Andrey Karpov

60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста
Andrey Karpov
 
60 terrible tips for a C++ developer
60 terrible tips for a C++ developer60 terrible tips for a C++ developer
60 terrible tips for a C++ developer
Andrey Karpov
 
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Andrey Karpov
 
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesPVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error Examples
Andrey Karpov
 
PVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature OverviewPVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature Overview
Andrey Karpov
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибок
Andrey Karpov
 
PVS-Studio в 2021
PVS-Studio в 2021PVS-Studio в 2021
PVS-Studio в 2021
Andrey Karpov
 
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Andrey Karpov
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
Andrey Karpov
 
Does static analysis need machine learning?
Does static analysis need machine learning?Does static analysis need machine learning?
Does static analysis need machine learning?
Andrey Karpov
 
Typical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and JavaTypical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and Java
Andrey Karpov
 
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
Andrey Karpov
 
Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?
Andrey Karpov
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical Reviewer
Andrey Karpov
 
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source SoftwareThe Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
Andrey Karpov
 
Static Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal EngineStatic Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal Engine
Andrey Karpov
 
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded SystemsSafety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Andrey Karpov
 
The Great and Mighty C++
The Great and Mighty C++The Great and Mighty C++
The Great and Mighty C++
Andrey Karpov
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
Andrey Karpov
 
Zero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for youZero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for you
Andrey Karpov
 

More from Andrey Karpov (20)

60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста
 
60 terrible tips for a C++ developer
60 terrible tips for a C++ developer60 terrible tips for a C++ developer
60 terrible tips for a C++ developer
 
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
 
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesPVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error Examples
 
PVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature OverviewPVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature Overview
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибок
 
PVS-Studio в 2021
PVS-Studio в 2021PVS-Studio в 2021
PVS-Studio в 2021
 
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
Does static analysis need machine learning?
Does static analysis need machine learning?Does static analysis need machine learning?
Does static analysis need machine learning?
 
Typical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and JavaTypical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and Java
 
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
 
Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical Reviewer
 
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source SoftwareThe Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
 
Static Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal EngineStatic Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal Engine
 
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded SystemsSafety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
 
The Great and Mighty C++
The Great and Mighty C++The Great and Mighty C++
The Great and Mighty C++
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
 
Zero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for youZero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for you
 

Паттерны 64-битных ошибок в играх

  • 1. Паттерны 64-битных ошибок в играх Андрей Карпов karpov@viva64.com
  • 2.
  • 3. Докладчик • Карпов Андрей Николаевич • На Хабр: habr.com/users/Andrey2008/ • Microsoft MVP, Intel Black Belt Software Developer • Один из основателей проекта PVS-Studio, который как раз начинался с поиска 64-битных ошибок • https://www.viva64.com
  • 5. Практика • 64-битные ошибки – это ошибки, которые начинают проявлять себя после сборки 64-битного приложения • Причём многие только когда пересекается граница 4 Гигабайта
  • 6. Пояснение на примере malloc • Кто увидит ошибку?
  • 7. void Foo() { const size_t Gigabyte = 1073741824; void *A[10]; for (size_t i = 0; i < 10; ++i) { A[i] = malloc(Gigabyte); printf("%pn", A[i]); } for (size_t i = 0; i < 10; ++i) free(A[i]); }
  • 8.
  • 9. В C-коде забывают подключать заголовочные файлы • В вашей программе может не быть вызовов malloc, но они могут быть в сторонних библиотеках • Проявляется только при потреблении большого объема памяти #include <stdio.h> #include <string.h> //#include <stdlib.h>
  • 10. И дело не только в malloc • Fennec Media • memset • memcpy • Ffdshow (media decoder) • memset • memcpy • libZPlay • strlen
  • 12. Тип long в Win64 const std::vector<Vec2> &vertexList = body->getCalculatedVertexList(); unsigned long length = vertexList.size(); PVS-Studio: V103 Implicit type conversion from memsize to 32-bit type. CCArmature.cpp 614 Cocos2d-x
  • 13. Тип int – плохая идея в любом случае PVS-Studio: V104 Implicit conversion of 'i' to memsize type in an arithmetic expression: i < points_.size() sweep_context.cc 76 std::vector<Point*> points_; void SweepContext::InitTriangulation() { // Calculate bounds. for (unsigned int i = 0; i < points_.size(); i++) { Point& p = *points_[i]; .... Cocos2d-x
  • 14. Кстати, такие ошибки намного коварнее, чем кажутся • При переполнении int возникает неопределённое поведение • UB – это, в том числе, когда всё работает правильно :) • Подробности: "Undefined behavior ближе, чем вы думаете" https://www.viva64.com/ru/b/0374/ size_t N = foo(); for (int i = 0; i < N; ++i)
  • 16. "memsize" типы • ptrdiff_t - знаковый тип (дистанция между указателями) • size_t - максимальный размер теоретически возможного объекта любого типа, включая массивы • rsize_t - размер одиночного объекта • intptr_t - знаковый тип, может хранить указатель • uintptr_t - беззнаковый тип, может хранить указатель
  • 17. Использование memsize-типов • Количество элементов в массиве • Размер буфера • Счётчики • Хранение указателя (хотя так лучше не делать) • Адресная арифметика • и так далее
  • 18. Использование memsize-типов: плохо PVS-Studio: V109 Implicit type conversion of return value 'a * b * c' to memsize type. test.cpp 22 Потенциальное переполнение size_t Foo(int a, int b, int c) { return a * b * c; }
  • 19. Использование memsize-типов: OK size_t Foo(int a, int b, int c) { return static_cast<size_t>(a) * static_cast<size_t>(b) * static_cast<size_t>(c); } size_t Foo(int a, int b, int c) { return static_cast<size_t>(a) * b * c; }
  • 20. ТОЛЬКО НЕ ДЕЛАЙТЕ ТАК! std::vector<unsigned char> buf( static_cast<size_t>(exr_image->width * h * pixel_data_size)); PVS-Studio: V1028 CWE-190 Possible overflow. Consider casting operands, not the result. tinyexr.h 11682 Вновь потенциальное переполнение TinyEXR
  • 21. Так ошибки только больше маскируются if (components == 1) { images[0].resize(static_cast<size_t>(width * height)); memcpy(images[0].data(), data, sizeof(float) * size_t(width * height)); } else { images[0].resize(static_cast<size_t>(width * height)); images[1].resize(static_cast<size_t>(width * height)); images[2].resize(static_cast<size_t>(width * height)); images[3].resize(static_cast<size_t>(width * height)); for (size_t i = 0; i < static_cast<size_t>(width * height); i++) { TinyEXR
  • 22. Ещё про адресную арифметику int A = -2; unsigned B = 1; int array[5] = { 1, 2, 3, 4, 5 }; int *ptr = array + 3; ptr = ptr + (A + B); printf("%in", *ptr); //Access violation //on 64-bit platform
  • 24. int64_t X = 1 << N • Этот код не работает и в 32-битных программах • Но там обычно и не понадобится выставлять старшие биты
  • 25. class FMallocBinned : public FMalloc { uint64 PoolMask; .... FMallocBinned(uint32 InPageSize, uint64 AddressLimit) { .... PoolMask = (( 1 << ( HashKeyShift - PoolBitShift ) ) - 1); .... } }; Unreal Engine 4 PVS-Studio: V629 Consider inspecting the '1 << (HashKeyShift - PoolBitShift)' expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64- bit type. mallocbinned.h 800
  • 26. class FMallocBinned : public FMalloc { uint64 PoolMask; .... FMallocBinned(uint32 InPageSize, uint64 AddressLimit) { .... PoolMask = (( 1ULL << ( HashKeyShift - PoolBitShift ) ) - 1); .... } }; Unreal Engine 4
  • 27. Godot Engine void vp9_adjust_mask(....) { .... const uint64_t columns = cm->mi_cols - mi_col; const uint64_t mask_y = (((1 << columns) - 1)) * 0x0101010101010101ULL; .... } PVS-Studio: V629 CWE-190 Consider inspecting the '1 << columns' expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. vp9_loopfilter.c 851
  • 28. size_t N = ~0U; • В 32-битном коде всё OK • 64-битный код, ожидание: 0xFFFFFFFFFFFFFFFF • 64-битный код, реальность: 0x00000000FFFFFFFF
  • 29. size_t nRenderMeshSize = ~0U; PVS-Studio: V101 Implicit assignment type conversion to memsize type. StatObjLoad.cpp 1369 CryEngine
  • 30. size_t N = ~(1024u - 1); • В 32-битном коде всё OK • 64-битный код, ожидание: 0xFFFFFFFFFFFFFC00 • 64-битный код, реальность: 0x00000000FFFFFC00
  • 31. static const UINT_PTR SmallBlockAlignMask = ~(SmallBlockLength - 1); FreeBlockHeader* InsertFreeBlock(FreeBlockHeader* after, UINT_PTR start, UINT_PTR end) { bool isFreeBlockDone = (start & SmallBlockAlignMask) == (end & SmallBlockAlignMask) || (start > end - (SmallBlockLength / 2)); .... } CryEngine
  • 32. Увеличенное потребление стека и динамической памяти
  • 33. Стек • Предлагаю не думать и просто увеличить его в 2 раза :)
  • 34. Динамическая память • Есть смысл повоевать • Везде ли нужны 64-битные целочисленные типы? • Везде ли нужны указатели? • Размер структур
  • 35. Избыточный рост размера структур struct Candidate { uint32_t face; ChartBuildData *chart; float metric; }; PVS-Studio: V802 On 64-bit platform, structure size can be reduced from 24 to 16 bytes by rearranging the fields according to their sizes in decreasing order. xatlas.cpp 5237 24 байта
  • 36. Избыточный рост размера структур struct Candidate { ChartBuildData *chart; uint32_t face; float metric; }; 16 байт
  • 39. Магические константы • 1024 x 768 • 1600 x 1200 • 4 • 32 • 0x7FFFFFFF • 0x80000000 • 0xFFFFFFFF
  • 40. Опасные трюки с приведением типов ResourceBase::Header *header = (*iter).value; char fourCC[ 5 ]; *( ( U32* ) fourCC ) = header->getSignature(); fourCC[ 4 ] = 0; Здесь из-за header всё будет хорошо, но всё это очень нестабильно. PVS-Studio: V1032 The pointer 'fourCC' is cast to a more strictly aligned pointer type. resourceManager.cpp 127 Torque 3D
  • 41. Сериализация данных • Нет конкретных ошибок и советов • Сделайте Code-Review
  • 46. Уточнить стандарт кодирования • Использовать правильные типы: ptrdiff_t, size_t, intptr_t, uintptr_t, INT_PTR, DWORD_PTR и т.д. • Нет магическим числам. Использовать: UINT_MAX, ULONG_MAX, std::numeric_limits<size_t>::max() и т.д. • Объяснить, как правильно пользоваться явным приведением типов в выражениях, и чем 1 отличается от static_cast<size_t>(1) • unsigned long != size_t
  • 50. Заключение • Даже если вы уже выпустили 64-битное приложение, это не значит, что оно работает • 64-битная ошибка может выжидать годами • Как улучшить ситуацию: • обучение • стандарт кодирования • статический анализ кода
  • 51. Полезные ссылки • Уроки разработки 64-битных приложений на языке Си/Си++ https://www.viva64.com/ru/l/full/ • Коллекция примеров 64-битных ошибок в реальных программах https://www.viva64.com/ru/a/0065/ • Undefined behavior ближе, чем вы думаете https://www.viva64.com/ru/b/0374/
  • 52. Ответы на вопросы Андрей Карпов karpov@viva64.com www.viva64.com