SlideShare ist ein Scribd-Unternehmen logo
1 von 22
Проблемы 64-битного кода на
примерах
Автор: Евгений Рыжков

Дата: 23.07.2007


Аннотация
Статья представляет собой рассмотрение примеров реальных проблем в Си++ коде,
проявляющихся при разработке 64-битных решений.

Данная статья содержит различные примеры 64-битных ошибок. Однако с момента ее написания,
мы узнали значительно больше примеров и типов ошибок, которые не описаны в этой статье. Мы
предлагаем вам познакомиться со статьей "Коллекция примеров 64-битных ошибок в реальных
программах", в которой наиболее полно описаны известные нам дефекты в 64-битных
программах. Также рекомендуем изучить "Уроки разработки 64-битных приложений на языке
Си/Си++", где описана методика создания корректного 64-битного кода и методы поиска всех
видов дефектов с использованием анализатора кода Viva64.


Введение
При переносе 32-битного программного обеспечения на 64-битные системы в коде приложений,
написанных на языке Си++, могут проявляться отсутствующие ранее ошибки. Причина этого
кроется в изменении базовых типов данных (а точнее, отношений между ними) на новой
аппаратной платформе. "Но ведь Си++ - высокоуровневый язык!", - воскликнете Вы и будете,
конечно же, правы. Однако все высокоуровневые абстракции этого языка реализуются через все
те же низкоуровневые типы данных.

Справочная документация для программистов, конечно же, содержит описание этих ошибок.
Однако даже такие авторитетные источники информации, как MSDN, зачастую пытаются
ограничиться лишь общими фразами, например:

   •   Типы int и long остались 32-битными на 64-битных версиях Windows;
   •   Типы size_t, time_t, и ptrdiff_t стали 64-битными на 64-битных версиях Windows.

Однако, что это означает для программиста, и в какие потенциальные проблемы может вылиться,
зачастую не сообщается.

Между тем статей, содержащих конкретные примеры ошибок в коде приложений для 64-битных
версий Windows, совсем мало. Настоящая статья и призвана восполнить этот пробел.

Немного терминологии. Под memsize-типом будем понимать любой тип данных, который меняет
свой размер при изменении разрядности архитектуры с 32 бит на 64 бита. Примеры: size_t,
ptrdiff_t, DWORD_PTR, LONG_PTR и другие.

Сразу же оговоримся, что в данной статье лишь кратко приводятся примеры ошибок. Объяснение
их причин можно найти в статье "20 ловушек переноса Си++ кода на 64-битную платформу"
http://www.viva64.com/art-1-2-599168895.html
Исходный код примера с ошибками
Не будем томить программистов, желающих поскорее приступить к изучению примеров ошибок,
и приведем полный исходный код такой программы. После исходного кода, каждая ошибка будет
рассмотрена отдельно.

Для демонстрации ошибок необходимо скомпилировать и запустить данный код в 64-битном
режиме.

Вы можете найти исходный код приложения в дистрибутиве Viva64 под названием PortSample.
Для этого скачайте и установите Viva64 (www.viva64.com/download.php), а затем установите
PortSample из программной группы Viva64.

bool IsX64Platform() {

    return sizeof(size_t) == 8;

}

template <typename A, typename B>

inline size_t SafeMul(A a, B b) {

    return static_cast<size_t>(a) * static_cast<size_t>(b);

}

template <typename A, typename B, typename C>

inline size_t SafeMul(A a, B b, C c) {

    return static_cast<size_t>(a) * static_cast<size_t>(b) *

     static_cast<size_t>(c);

}

template <typename A, typename B, typename C, typename D>

inline size_t SafeMul(A a, B b, C c, D d) {

    return static_cast<size_t>(a) * static_cast<size_t>(b) *

           static_cast<size_t>(c) * static_cast<size_t>(d);

}

void V101()

{

    unsigned imageWidth = 1000;

    unsigned imageHeght = 1000;

    unsigned bytePerPixel = 3;

    unsigned maxFrameCountInBuffer;
if (IsX64Platform()) {

        maxFrameCountInBuffer = 2000;

    } else {

        maxFrameCountInBuffer = 100;

    }

    size_t bufferSize = imageWidth * imageHeght *

                          bytePerPixel * maxFrameCountInBuffer;

    BYTE *buffer = static_cast<BYTE *>(malloc(bufferSize));

    BYTE *ptr = buffer;

    for (unsigned frame = 0; frame != maxFrameCountInBuffer; ++frame)

        for (unsigned width = 0; width != imageWidth; ++width)

         for (unsigned height = 0; height != imageHeght; ++height) {

             *ptr++ = 0xFF;

             *ptr++ = 0xFF;

             *ptr++ = 0x00;

         }

    free (buffer);

}

void V102()

{

    int domainWidth;

    int domainHeght;

    int domainDepth;

    if (IsX64Platform()) {

        domainWidth = 2000;

        domainHeght = 2000;

        domainDepth = 2000;

    } else {

        domainWidth = 500;

        domainHeght = 500;
domainDepth = 500;

    }



    char *buffer =

    new char [size_t(domainWidth) * size_t(domainHeght) *
size_t(domainDepth)];



    char *current = buffer;

    char *end = buffer;

    end += domainWidth * domainHeght * domainDepth;

    while (current != end)

        *current++ = 1;

    delete [] buffer;

}

void V103()

{

    size_t Megabyte = 1048576;

    size_t Gigabyte = 1073741824;

    size_t n = IsX64Platform() ? Gigabyte : Megabyte;

    unsigned arraySize = n * sizeof(INT_PTR);

    INT_PTR *buffer = (INT_PTR *)malloc(size_t(arraySize));

    for (size_t i = 0; i != n; ++i)

        buffer[i] = 0;

    free(buffer);

}

void V104()

{

    volatile size_t n;

    if (IsX64Platform()) {

        n = SafeMul(5, 1024, 1024, 1024);
} else {

        n = SafeMul(5, 1024, 1024);

    }



    char *buffer = new char [n];



    volatile size_t index = 0;

    volatile unsigned i;

    for (i = 0; i != n; ++i)

        buffer[index++] = 1;

    delete [] buffer;

}

void V105()

{

    bool flag = true;

    unsigned a = unsigned(-1);

    if ((flag ? a : sizeof(float)) != size_t(-1)) {

        throw CString("x64 portability issues");

    }

}

void V106()

{

    void *buffer;

    const unsigned Megabyte = 1024 * 1024;

    const unsigned Gigabyte = 1024 * 1024 * 1024;

    unsigned unit;

    if (IsX64Platform())

        unit = Gigabyte;

    else

        unit = Megabyte;
buffer = malloc(5 * unit);

    if (IsX64Platform())

        memset(buffer, 0, SafeMul(5, 1024, 1024, 1024));

    else

        memset(buffer, 0, SafeMul(5, 1024, 1024));

    free(buffer);

}

void V107_FillFunction(char *array, unsigned arraySize) {

    for (unsigned i = 0; i != arraySize; ++i)

        array[i] = 1;

}

void V107()

{

    size_t n;

    if (IsX64Platform()) {

        n = SafeMul(5, 1024, 1024, 1024);

    } else {

        n = SafeMul(5, 1024, 1024);

    }

    char *array = (char *)malloc(n * sizeof(char));

    memset(array, 0, n * sizeof(char));

    V107_FillFunction(array, n);

    for (size_t i = 0; i != n; ++i)

        if (array[i] != 1)

         throw CString("x64 portability issues");

    free(array);

}

void V108()

{

    size_t n;
if (IsX64Platform()) {

        n = SafeMul(5, 1024, 1024, 1024);

    } else {

        n = SafeMul(5, 1024, 1024);

    }

    char *array = (char *)malloc(n * sizeof(char));

    memset(array, 0, n * sizeof(char));

    volatile int index = 0;

    for (size_t i = 0; i != n; ++i) {

        array[index++] = 1;

        if (array[i] != 1)

         throw CString("x64 portability issues");

    }

    free(array);

}

ptrdiff_t UnsafeCalcIndex(int x, int y, int width) {

    volatile int result = x + y * width;

    return result;

}

void V109()

{

    int domainWidth;

    int domainHeght;

    if (IsX64Platform()) {

        domainWidth = 50000;

        domainHeght = 50000;

    } else {

        domainWidth = 5000;

        domainHeght = 5000;

    }
char *array = (char *)malloc(SafeMul(domainWidth, domainHeght));

    for (int x = 0; x != domainWidth; ++x)

        for (int y = 0; y != domainHeght; ++y) {

            array[UnsafeCalcIndex(x, y, domainWidth)] = 55;

        }

    free(array);

}

int UnsafeStrLen(const char *text) {

    const char *ptr = text;

    while (*ptr != 0)

        ++ptr;

    return ptr - text;

}

void V110()

{

    size_t n;

    CString trueSize;

    if (IsX64Platform()) {

        n = SafeMul(3, 1024, 1024, 1024);

        trueSize = _T("3221225472");

    } else {

        n = SafeMul(3, 1024, 1024);

        trueSize = _T("3145728");

    }

    char *str = (char *)malloc(n * sizeof(char));

    memset(str, 'V', n * sizeof(char));

    str[n - 1] = 0;

    int len = UnsafeStrLen(str);

    CString falseSize;

    falseSize.Format(_T("%i"), len + 1);
free(str);

    if (falseSize != trueSize)

     throw CString(_T("x64 portability issues"));

}

void V111()

{

    char invalidStr[100], validStr[100];

    const char *invalidFormat = "%u";

    const char *validFormat = "%Iu";

    size_t a = SIZE_MAX;

    sprintf_s(invalidStr, sizeof(invalidStr),invalidFormat, a);

    sprintf_s(validStr, sizeof(validStr), validFormat, a);

    if (strcmp(invalidStr, validStr) != 0)

     throw CString(_T("x64 portability issues"));

}

void V113()

{

    size_t a = size_t(-1);

    double b = a;

    --a;

    --b;

    size_t c = b;

    if (a != c)

     throw CString(_T("x64 portability issues"));

}

void V114()

{

    unsigned intPtr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    size_t *sizetPtr = (size_t *)(intPtr);

    size_t sum = 0;
for (size_t i = 0; i != 10; ++i)

     sum += sizetPtr[i];

    if (sum != 45)

     throw CString(_T("x64 portability issues"));

}

void V301()

{

    class CWinAppTest {

    public:

     virtual void WinHelp(DWORD_PTR, UINT) {

         ::AfxMessageBox(_T("Cannot activate WinHelp"));

     }

    };

    class CPortSampleApp : public CWinAppTest {

    public:

     virtual void WinHelp(DWORD, UINT) {

         ::AfxMessageBox(_T("WinHelp activated"));

     }

    };

    CWinAppTest *Application = new CPortSampleApp();

    Application->WinHelp(NULL, 0);

    delete Application;

}

int _tmain(int argc, TCHAR* argv[])

{

    V101();

    V102();

    V103();

    V104();

    V105();
V106();

    V107();

    V108();

    V109();

    V110();

    V111();

    V112();

    V113();

    V114();

    V201();

    V202();

    V203();

    V301();

    return 0;

}

Теперь, когда Вы увидели весь код, давайте рассмотрим все функции, содержащие ошибки. Когда
мы говорим, что функции содержат ошибки, мы имеем в виду следующее. Представленный код
прекрасно компилируется и работает в 32-битном режиме. Однако, после компиляции для 64-
битного режима, работа программы становится некорректной, вплоть до падений.


Неявное приведение к типу memsize
void V101()

{

    unsigned imageWidth = 1000;

    unsigned imageHeght = 1000;

    unsigned bytePerPixel = 3;

    unsigned maxFrameCountInBuffer;

    if (IsX64Platform()) {

        maxFrameCountInBuffer = 2000;

    } else {

        maxFrameCountInBuffer = 100;

    }
size_t bufferSize = imageWidth * imageHeght *

                           bytePerPixel * maxFrameCountInBuffer;

    BYTE *buffer = static_cast<BYTE *>(malloc(bufferSize));

    BYTE *ptr = buffer;

    for (unsigned frame = 0; frame != maxFrameCountInBuffer; ++frame)

     for (unsigned width = 0; width != imageWidth; ++width)

       for (unsigned height = 0; height != imageHeght; ++height) {

           *ptr++ = 0xFF;

           *ptr++ = 0xFF;

           *ptr++ = 0x00;

       }

    free (buffer);

}

Проблема скрыта в следующей строке:

size_t bufferSize = imageWidth * imageHeght *

                           bytePerPixel * maxFrameCountInBuffer;

Все переменные, участвующие в умножении, имеют тип unsigned, который и в 32-х и 64-битном
режиме имеет размер 32 бита. Однако результат умножения записывается в переменную типа
size_t, который в 32-битном режиме имеет размер, совпадающий с размером типа unsigned, а в
64-битном - не совпадающий. Но компилятор прекрасно выполняет расширение результирующего
типа до unsigned. Казалось бы, проблемы нет? Есть! Если в результате умножения результат
превысит 4 гигабайта, то переполнение произойдет и результат будет неверным.


Использование не memsize-типа для арифметики с указателями
void V102()

{

    int domainWidth;

    int domainHeght;

    int domainDepth;

    if (IsX64Platform()) {

     domainWidth = 2000;

     domainHeght = 2000;
domainDepth = 2000;

    } else {

        domainWidth = 500;

        domainHeght = 500;

        domainDepth = 500;

    }



    char *buffer =

    new char [size_t(domainWidth) * size_t(domainHeght) *
size_t(domainDepth)];



    char *current = buffer;

    char *end = buffer;

    end += domainWidth * domainHeght * domainDepth;

    while (current != end)

        *current++ = 1;

    delete [] buffer;

}

Проблема в данном коде заключается в арифметике с указателями, точнее в использовании для
этой арифметики не memsize-типов:

    end += domainWidth * domainHeght * domainDepth;

Ошибка в том, что на 64-битной платформе указатель end никогда не получит приращение более 4
гигабайт.


Неявное приведение memsize-типа
void V103()

{

    size_t Megabyte = 1048576;

    size_t Gigabyte = 1073741824;

    size_t n = IsX64Platform() ? Gigabyte : Megabyte;

    unsigned arraySize = n * sizeof(INT_PTR);

    INT_PTR *buffer = (INT_PTR *)malloc(size_t(arraySize));
for (size_t i = 0; i != n; ++i)

        buffer[i] = 0;

    free(buffer);

}

В следующем фрагменте кода присутствует совершенно очевидная ошибка:

    unsigned arraySize = n * sizeof(INT_PTR);

Это неявное приведение к unsigned-типу переменной большей разрядности (на 64-битной
платформе).


Неявное приведение к memsize-типу в арифметическом выражении
void V104()

{

    volatile size_t n;

    if (IsX64Platform()) {

        n = SafeMul(5, 1024, 1024, 1024);

    } else {

        n = SafeMul(5, 1024, 1024);

    }



    char *buffer = new char [n];



    volatile size_t index = 0;

    volatile unsigned i;

    for (i = 0; i != n; ++i)

        buffer[index++] = 1;

    delete [] buffer;

}

Операции вроде сравнения двух переменных, как ни странно, также могут стать источником
проблем.

В следующей строке:

    for (i = 0; i != n; ++i)
проблема в том, что переменная i типа unsigned сравнивается с переменной n типа size_t, после
чего происходит ее увеличение. Однако из-за того, что unsigned никогда не превышает 4 гигабайт,
то переменная i никогда не будет больше этого значения. Что мы имеем в результате?
Бесконечный цикл, так как условие i != n будет выполняться всегда.


Неявное приведение к memsize типу в операции ?:
void V105()

{

    bool flag = true;

    unsigned a = unsigned(-1);

    if ((flag ? a : sizeof(float)) != size_t(-1)) {

        throw CString("x64 portability issues");

    }

}

Этот пример очень похож на предыдущий. Проблема в следующей строке:

    if ((flag ? a : sizeof(float)) != size_t(-1)) {

Здесь переменная a имеет тип unsigned, который при сравнении с size_t может дать некорректный
результат. Почему? Да потому, что unsigned(-1) - это не тоже самое, что size_t (-1). Неявное
приведение аргумента функции к memsize-типу.

void V106()

{

    void *buffer;

    const unsigned Megabyte = 1024 * 1024;

    const unsigned Gigabyte = 1024 * 1024 * 1024;

    unsigned unit;

    if (IsX64Platform())

        unit = Gigabyte;

    else

        unit = Megabyte;

    buffer = malloc(5 * unit);

    if (IsX64Platform())

        memset(buffer, 0, SafeMul(5, 1024, 1024, 1024));
else

        memset(buffer, 0, SafeMul(5, 1024, 1024));

    free(buffer);

}

В строке:

    buffer = malloc(5 * unit);

программист рассчитывал получить на 64-битной системе буфер из 5 гигабайт. Однако здесь
произойдет ошибка. Почему? Функция malloc() принимает аргумент memsize-типа и 5 гигабайт -
вполне подходящее число. Однако при умножении (5 * unit) произойдет переполнение, т.к.
переменная unit имеет тип unsigned. В результате получится вовсе не 5 гигабайт.


Неявное приведение аргумента функции memsize-типа к 32-
битному типу
void V107_FillFunction(char *array, unsigned arraySize) {

    for (unsigned i = 0; i != arraySize; ++i)

        array[i] = 1;

}

void V107()

{

    size_t n;

    if (IsX64Platform()) {

        n = SafeMul(5, 1024, 1024, 1024);

    } else {

        n = SafeMul(5, 1024, 1024);

    }

    char *array = (char *)malloc(n * sizeof(char));

    memset(array, 0, n * sizeof(char));

    V107_FillFunction(array, n);

    for (size_t i = 0; i != n; ++i)

        if (array[i] != 1)

         throw CString("x64 portability issues");

    free(array);
}

В строке, с вызовом функции

    V107_FillFunction(array, n);

происходит приведение типа переменной n к unsigned. Это означает усечение значения
переменной, в результате чего может быть заполнен не весь массив.


Использование для индексации некорректных типов
void V108()

{

    size_t n;

    if (IsX64Platform()) {

        n = SafeMul(5, 1024, 1024, 1024);

    } else {

        n = SafeMul(5, 1024, 1024);

    }

    char *array = (char *)malloc(n * sizeof(char));

    memset(array, 0, n * sizeof(char));

    volatile int index = 0;

    for (size_t i = 0; i != n; ++i) {

        array[index++] = 1;

        if (array[i] != 1)

         throw CString("x64 portability issues");

    }

    free(array);

}

Если для индексации массива использовать не memsize-тип, то может произойти ошибка вида:

array[index++] = 1;

Проблема состоит в том, что в случае если в массиве присутствует более 4 гигабайт элементов, то
обратится к ним с помощью переменной типа unsigned будет невозможно.
Приведение к memsize-типу при использовании возвращаемого
значения
ptrdiff_t UnsafeCalcIndex(int x, int y, int width) {

    volatile int result = x + y * width;

    return result;

}

void V109()

{

    int domainWidth;

    int domainHeght;

    if (IsX64Platform()) {

        domainWidth = 50000;

        domainHeght = 50000;

    } else {

        domainWidth = 5000;

        domainHeght = 5000;

    }

    char *array = (char *)malloc(SafeMul(domainWidth, domainHeght));

    for (int x = 0; x != domainWidth; ++x)

        for (int y = 0; y != domainHeght; ++y) {

            array[UnsafeCalcIndex(x, y, domainWidth)] = 55;

        }

    free(array);

}

Удивительно, но в данном примере ошибка содержится в строке:

    return result;

Переменная result имеет тип int, который неявно будет расширен до ptrdiff_t. Однако функция
UnsafeCalcIndex() никогда не сможет вернуть индекс элемента, следующего за 2 гигабайтами.
Конечно, правильнее сказать, что ошибка в неудачно выбранном типе переменной result. Эта
переменная в данном случае должна иметь тип ptrdiff_t.
Приведение memsize-типа при использовании возвращаемого
значения
int UnsafeStrLen(const char *text) {

    const char *ptr = text;

    while (*ptr != 0)

        ++ptr;

    return ptr - text;

}

void V110()

{

    size_t n;

    CString trueSize;

    if (IsX64Platform()) {

        n = SafeMul(3, 1024, 1024, 1024);

        trueSize = _T("3221225472");

    } else {

        n = SafeMul(3, 1024, 1024);

        trueSize = _T("3145728");

    }

    char *str = (char *)malloc(n * sizeof(char));

    memset(str, 'V', n * sizeof(char));

    str[n - 1] = 0;

    int len = UnsafeStrLen(str);

    CString falseSize;

    falseSize.Format(_T("%i"), len + 1);

    if (falseSize != trueSize)

        throw CString(_T("x64 portability issues"));

}

Ситуация повторяет предыдущий пример, ошибка опять в строке возврата значения:

    return ptr - text;
Отличие лишь в том, что здесь выполняется приведение memsize типа к типу int. В результате
размер буфера (из примера) никогда не сможет быть вычислен в случае, если он больше 2
гигабайт.


Вызов функции с переменным числом аргументов с memsize-
параметром
void V111()

{

    char invalidStr[100], validStr[100];

    const char *invalidFormat = "%u";

    const char *validFormat = "%Iu";

    size_t a = SIZE_MAX;

    sprintf_s(invalidStr, sizeof(invalidStr),invalidFormat, a);

    sprintf_s(validStr, sizeof(validStr), validFormat, a);

    if (strcmp(invalidStr, validStr) != 0)

     throw CString(_T("x64 portability issues"));

}

Функции с переменным числом аргументов очень часто используются для форматирования и
ввода/вывода текстовых строк. Некорректное задание строки формата может привести к
неправильной работе:

    const char *invalidFormat = "%u";

    sprintf_s(invalidStr, sizeof(invalidStr),invalidFormat, a);

Строка формата в данном примере рассчитана на 32-битный режим работы и в 64-битном режиме
приведет к неправильному выводу.


Неявное приведение memsize-типа к double и наоборот
void V113()

{

    size_t a = size_t(-1);

    double b = a;

    --a;

    --b;

    size_t c = b;
if (a != c)

     throw CString(_T("x64 portability issues"));

}

В представленном примере ошибки содержатся в строках:

double b = a;

и

size_t c = b;

Такое присваивание на 64-битных системах некорректно, так как может вызвать потерю точности.


Явные приведения типов при работе с указателями
void V114()

{

    unsigned intPtr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    size_t *sizetPtr = (size_t *)(intPtr);

    size_t sum = 0;

    for (size_t i = 0; i != 10; ++i)

     sum += sizetPtr[i];

    if (sum != 45)

     throw CString(_T("x64 portability issues"));

}

Язык Си++, являясь низкоуровневым языком, позволяет работать с памятью на уровне указателей.
Явные приведения типов при использовании указателей являются опасными в любом случае,
однако приведение memsize типов как показано в примере, вдвойне опаснее:

    size_t *sizetPtr = (size_t *)(intPtr);

Все дело в разности размеров типов size_t и unsigned.


Перекрытие виртуальных функций
void V301()

{

    class CWinAppTest {

    public:

     virtual void WinHelp(DWORD_PTR, UINT) {
::AfxMessageBox(_T("Cannot activate WinHelp"));

     }

    };

    class CPortSampleApp : public CWinAppTest {

    public:

     virtual void WinHelp(DWORD, UINT) {

         ::AfxMessageBox(_T("WinHelp activated"));

     }

    };

    CWinAppTest *Application = new CPortSampleApp();

    Application->WinHelp(NULL, 0);

    delete Application;

}

Одна из самых забавных ошибок в Си++ приложениях, которая может проявиться на 64-битных
системах, связана с виртуальными функциями. Обратите внимание на параметры виртуальных
функций в примере выше. На 32-битной системе DWORD_PTR и DWORD совпадают, и получается
перекрытая виртуальная функция, а на 64-битной - это две разных функции! В результате вызов
функции WinHelp() из примера приведет к появлению сообщения "Cannot activate WinHelp".


Вместо заключения
Итак, мы перечислили основные ошибки в коде, которые проявляются при переносе приложений
на 64-битные системы? Вы скажете, что многие из них надуманы? Кому, например, может
понадобиться буфер в 5 гигабайт на Windows-системе? Может быть, в 2007 году, это еще и не
столь актуально, хотя многие ресурсоемкие приложения уже могут использовать такой объем
памяти. Однако посмотрим, будет ли востребована эта статья уже через пару лет. Кто знает,
может быть именно Вы будете долго отлаживать ошибку, возникающую при выделении
нескольких гигабайт памяти.


Информация об авторе
Евгений Рыжков, один из создателей статического анализатора кода Viva64 (www.Viva64.com),
предназначенного для упрощения переноса приложений на 64-битные платформы. Исследует
проблемы миграции 32-битных программных систем на 64-битные платформы.

Weitere ähnliche Inhalte

Was ist angesagt?

ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...Alexey Paznikov
 
Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Mikhail Kurnosov
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...Alexey Paznikov
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
 
Продолжаем говорить про арифметику
Продолжаем говорить про арифметикуПродолжаем говорить про арифметику
Продолжаем говорить про арифметикуAndrey Akinshin
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Mikhail Kurnosov
 
Поговорим про арифметику
Поговорим про арифметикуПоговорим про арифметику
Поговорим про арифметикуAndrey Akinshin
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийMikhail Shcherbakov
 
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“Platonov Sergey
 
Продолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийПродолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийAndrey Akinshin
 
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...Alexey Paznikov
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
 
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...Alexey Paznikov
 
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMSergey Platonov
 
презентация
презентацияпрезентация
презентацияLIANA180
 
How to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life longHow to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life longTimur Shemsedinov
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...Alexey Paznikov
 
Лекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиЛекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиMikhail Kurnosov
 
Обработка коллекций. Единая суть и множество проявлений
Обработка коллекций. Единая суть и множество проявленийОбработка коллекций. Единая суть и множество проявлений
Обработка коллекций. Единая суть и множество проявленийcorehard_by
 

Was ist angesagt? (20)

ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
 
Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
 
Продолжаем говорить про арифметику
Продолжаем говорить про арифметикуПродолжаем говорить про арифметику
Продолжаем говорить про арифметику
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)
 
Поговорим про арифметику
Поговорим про арифметикуПоговорим про арифметику
Поговорим про арифметику
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложений
 
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
 
Продолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийПродолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложений
 
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
 
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
 
презентация
презентацияпрезентация
презентация
 
How to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life longHow to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life long
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
 
Лекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиЛекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимости
 
Обработка коллекций. Единая суть и множество проявлений
Обработка коллекций. Единая суть и множество проявленийОбработка коллекций. Единая суть и множество проявлений
Обработка коллекций. Единая суть и множество проявлений
 

Andere mochten auch

Danke an meine Kunden
Danke an meine KundenDanke an meine Kunden
Danke an meine Kundenalinadan
 
Workshop de Product Management Agil en Parque Informático La Punta
Workshop de Product Management Agil en Parque Informático La PuntaWorkshop de Product Management Agil en Parque Informático La Punta
Workshop de Product Management Agil en Parque Informático La PuntaRicardo Colusso
 
Presentación de la capacitación
Presentación de la capacitaciónPresentación de la capacitación
Presentación de la capacitaciónMarcebrise
 
44 seguridad y se linux
44  seguridad y se linux44  seguridad y se linux
44 seguridad y se linuxAprende Viendo
 
Expo administracion
Expo administracionExpo administracion
Expo administracionirving
 
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...VLADEMIRSS
 
Tarea 2 reseña_wismer_cruz
Tarea 2 reseña_wismer_cruzTarea 2 reseña_wismer_cruz
Tarea 2 reseña_wismer_cruzjhon1981
 
Redes sociales
Redes socialesRedes sociales
Redes socialesbeapach28
 
40 configuración del kernel y dispositivos
40  configuración del kernel y dispositivos40  configuración del kernel y dispositivos
40 configuración del kernel y dispositivosAprende Viendo
 
Predzazhita 2009 v16
Predzazhita 2009 v16Predzazhita 2009 v16
Predzazhita 2009 v16guest1ba51d
 
Anuncio da privatización
Anuncio da privatizaciónAnuncio da privatización
Anuncio da privatizaciónfabiogp7
 
PARA LOS AMANTES DE LOS ANIMALES
PARA LOS AMANTES DE LOS ANIMALESPARA LOS AMANTES DE LOS ANIMALES
PARA LOS AMANTES DE LOS ANIMALESMarit
 
Apm en Iir 1 día de Propuestas Ganadoras con Mariano Paredes
Apm en Iir 1 día de Propuestas Ganadoras con Mariano ParedesApm en Iir 1 día de Propuestas Ganadoras con Mariano Paredes
Apm en Iir 1 día de Propuestas Ganadoras con Mariano ParedesAPM-Shipley
 

Andere mochten auch (20)

Pasos2
Pasos2Pasos2
Pasos2
 
Danke an meine Kunden
Danke an meine KundenDanke an meine Kunden
Danke an meine Kunden
 
Trabajofinal 102058 150
Trabajofinal 102058 150Trabajofinal 102058 150
Trabajofinal 102058 150
 
Workshop de Product Management Agil en Parque Informático La Punta
Workshop de Product Management Agil en Parque Informático La PuntaWorkshop de Product Management Agil en Parque Informático La Punta
Workshop de Product Management Agil en Parque Informático La Punta
 
Presentación de la capacitación
Presentación de la capacitaciónPresentación de la capacitación
Presentación de la capacitación
 
44 seguridad y se linux
44  seguridad y se linux44  seguridad y se linux
44 seguridad y se linux
 
Expo administracion
Expo administracionExpo administracion
Expo administracion
 
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
 
Tarea 2 reseña_wismer_cruz
Tarea 2 reseña_wismer_cruzTarea 2 reseña_wismer_cruz
Tarea 2 reseña_wismer_cruz
 
Taller3 intenet
Taller3 intenetTaller3 intenet
Taller3 intenet
 
Redes sociales
Redes socialesRedes sociales
Redes sociales
 
Google apps[1]
Google apps[1]Google apps[1]
Google apps[1]
 
9 lvm
9  lvm9  lvm
9 lvm
 
40 configuración del kernel y dispositivos
40  configuración del kernel y dispositivos40  configuración del kernel y dispositivos
40 configuración del kernel y dispositivos
 
Predzazhita 2009 v16
Predzazhita 2009 v16Predzazhita 2009 v16
Predzazhita 2009 v16
 
Anuncio da privatización
Anuncio da privatizaciónAnuncio da privatización
Anuncio da privatización
 
PARA LOS AMANTES DE LOS ANIMALES
PARA LOS AMANTES DE LOS ANIMALESPARA LOS AMANTES DE LOS ANIMALES
PARA LOS AMANTES DE LOS ANIMALES
 
Infocentro - Alfabetización digital Practico
Infocentro - Alfabetización digital PracticoInfocentro - Alfabetización digital Practico
Infocentro - Alfabetización digital Practico
 
Informatica 1
Informatica 1Informatica 1
Informatica 1
 
Apm en Iir 1 día de Propuestas Ganadoras con Mariano Paredes
Apm en Iir 1 día de Propuestas Ganadoras con Mariano ParedesApm en Iir 1 día de Propuestas Ganadoras con Mariano Paredes
Apm en Iir 1 día de Propuestas Ganadoras con Mariano Paredes
 

Ähnlich wie Проблемы 64-битного кода на примерах

200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя:опыт статического анализа исходного кода200 open source проектов спустя:опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кодаPositive Hack Days
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кодаAndrey Karpov
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Sergey Platonov
 
Урок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаУрок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаTatyanazaxarova
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода Pavel Tsukanov
 
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
 Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ... Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...Yandex
 
Подводные камни System.Security.Cryptography
Подводные камни System.Security.CryptographyПодводные камни System.Security.Cryptography
Подводные камни System.Security.CryptographyVladimir Kochetkov
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиTatyanazaxarova
 
Статический и динамический полиморфизм в C++, Дмитрий Леванов
Статический и динамический полиморфизм в C++, Дмитрий ЛевановСтатический и динамический полиморфизм в C++, Дмитрий Леванов
Статический и динамический полиморфизм в C++, Дмитрий ЛевановYandex
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийOOO "Program Verification Systems"
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кодаTatyanazaxarova
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаAndrey Karpov
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийTatyanazaxarova
 
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...Andrey Karpov
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksMikhail Kurnosov
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибкиAndrey Karpov
 
Красивая 64-битная ошибка на языке Си
Красивая  64-битная ошибка на языке СиКрасивая  64-битная ошибка на языке Си
Красивая 64-битная ошибка на языке СиTatyanazaxarova
 

Ähnlich wie Проблемы 64-битного кода на примерах (20)

200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя:опыт статического анализа исходного кода200 open source проектов спустя:опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
 
Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++Павел Беликов, Как избежать ошибок, используя современный C++
Павел Беликов, Как избежать ошибок, используя современный C++
 
Урок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаУрок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметика
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
 Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ... Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
 
Подводные камни System.Security.Cryptography
Подводные камни System.Security.CryptographyПодводные камни System.Security.Cryptography
Подводные камни System.Security.Cryptography
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибки
 
Статический и динамический полиморфизм в C++, Дмитрий Леванов
Статический и динамический полиморфизм в C++, Дмитрий ЛевановСтатический и динамический полиморфизм в C++, Дмитрий Леванов
Статический и динамический полиморфизм в C++, Дмитрий Леванов
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кода
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
 
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
 
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кодаSECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибки
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибки
 
Красивая 64-битная ошибка на языке Си
Красивая  64-битная ошибка на языке СиКрасивая  64-битная ошибка на языке Си
Красивая 64-битная ошибка на языке Си
 

Mehr von Tatyanazaxarova

Урок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияУрок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияTatyanazaxarova
 
Урок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программУрок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программTatyanazaxarova
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокTatyanazaxarova
 
Урок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структурУрок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структурTatyanazaxarova
 
Урок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данныхУрок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данныхTatyanazaxarova
 
Урок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияУрок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияTatyanazaxarova
 
Урок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен даннымиУрок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен даннымиTatyanazaxarova
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхУрок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхTatyanazaxarova
 
Урок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателейУрок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателейTatyanazaxarova
 
Урок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметикаУрок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметикаTatyanazaxarova
 
Урок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаУрок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаTatyanazaxarova
 
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовУрок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовTatyanazaxarova
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаTatyanazaxarova
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокУрок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокTatyanazaxarova
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокTatyanazaxarova
 
Урок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеУрок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеTatyanazaxarova
 
Урок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияУрок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияTatyanazaxarova
 
Урок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииУрок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииTatyanazaxarova
 
PVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируетеPVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируетеTatyanazaxarova
 

Mehr von Tatyanazaxarova (20)

Урок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияУрок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окружения
 
Урок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программУрок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программ
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
 
Урок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структурУрок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структур
 
Урок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данныхУрок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данных
 
Урок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияУрок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. Исключения
 
Урок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен даннымиУрок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен данными
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхУрок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединениях
 
Урок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателейУрок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателей
 
Урок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметикаУрок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметика
 
Урок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаУрок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвига
 
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовУрок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числа
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокУрок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибок
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибок
 
Урок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеУрок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном коде
 
Урок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияУрок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложения
 
Урок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииУрок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурации
 
PVS-Studio
PVS-Studio PVS-Studio
PVS-Studio
 
PVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируетеPVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируете
 

Проблемы 64-битного кода на примерах

  • 1. Проблемы 64-битного кода на примерах Автор: Евгений Рыжков Дата: 23.07.2007 Аннотация Статья представляет собой рассмотрение примеров реальных проблем в Си++ коде, проявляющихся при разработке 64-битных решений. Данная статья содержит различные примеры 64-битных ошибок. Однако с момента ее написания, мы узнали значительно больше примеров и типов ошибок, которые не описаны в этой статье. Мы предлагаем вам познакомиться со статьей "Коллекция примеров 64-битных ошибок в реальных программах", в которой наиболее полно описаны известные нам дефекты в 64-битных программах. Также рекомендуем изучить "Уроки разработки 64-битных приложений на языке Си/Си++", где описана методика создания корректного 64-битного кода и методы поиска всех видов дефектов с использованием анализатора кода Viva64. Введение При переносе 32-битного программного обеспечения на 64-битные системы в коде приложений, написанных на языке Си++, могут проявляться отсутствующие ранее ошибки. Причина этого кроется в изменении базовых типов данных (а точнее, отношений между ними) на новой аппаратной платформе. "Но ведь Си++ - высокоуровневый язык!", - воскликнете Вы и будете, конечно же, правы. Однако все высокоуровневые абстракции этого языка реализуются через все те же низкоуровневые типы данных. Справочная документация для программистов, конечно же, содержит описание этих ошибок. Однако даже такие авторитетные источники информации, как MSDN, зачастую пытаются ограничиться лишь общими фразами, например: • Типы int и long остались 32-битными на 64-битных версиях Windows; • Типы size_t, time_t, и ptrdiff_t стали 64-битными на 64-битных версиях Windows. Однако, что это означает для программиста, и в какие потенциальные проблемы может вылиться, зачастую не сообщается. Между тем статей, содержащих конкретные примеры ошибок в коде приложений для 64-битных версий Windows, совсем мало. Настоящая статья и призвана восполнить этот пробел. Немного терминологии. Под memsize-типом будем понимать любой тип данных, который меняет свой размер при изменении разрядности архитектуры с 32 бит на 64 бита. Примеры: size_t, ptrdiff_t, DWORD_PTR, LONG_PTR и другие. Сразу же оговоримся, что в данной статье лишь кратко приводятся примеры ошибок. Объяснение их причин можно найти в статье "20 ловушек переноса Си++ кода на 64-битную платформу" http://www.viva64.com/art-1-2-599168895.html
  • 2. Исходный код примера с ошибками Не будем томить программистов, желающих поскорее приступить к изучению примеров ошибок, и приведем полный исходный код такой программы. После исходного кода, каждая ошибка будет рассмотрена отдельно. Для демонстрации ошибок необходимо скомпилировать и запустить данный код в 64-битном режиме. Вы можете найти исходный код приложения в дистрибутиве Viva64 под названием PortSample. Для этого скачайте и установите Viva64 (www.viva64.com/download.php), а затем установите PortSample из программной группы Viva64. bool IsX64Platform() { return sizeof(size_t) == 8; } template <typename A, typename B> inline size_t SafeMul(A a, B b) { return static_cast<size_t>(a) * static_cast<size_t>(b); } template <typename A, typename B, typename C> inline size_t SafeMul(A a, B b, C c) { return static_cast<size_t>(a) * static_cast<size_t>(b) * static_cast<size_t>(c); } template <typename A, typename B, typename C, typename D> inline size_t SafeMul(A a, B b, C c, D d) { return static_cast<size_t>(a) * static_cast<size_t>(b) * static_cast<size_t>(c) * static_cast<size_t>(d); } void V101() { unsigned imageWidth = 1000; unsigned imageHeght = 1000; unsigned bytePerPixel = 3; unsigned maxFrameCountInBuffer;
  • 3. if (IsX64Platform()) { maxFrameCountInBuffer = 2000; } else { maxFrameCountInBuffer = 100; } size_t bufferSize = imageWidth * imageHeght * bytePerPixel * maxFrameCountInBuffer; BYTE *buffer = static_cast<BYTE *>(malloc(bufferSize)); BYTE *ptr = buffer; for (unsigned frame = 0; frame != maxFrameCountInBuffer; ++frame) for (unsigned width = 0; width != imageWidth; ++width) for (unsigned height = 0; height != imageHeght; ++height) { *ptr++ = 0xFF; *ptr++ = 0xFF; *ptr++ = 0x00; } free (buffer); } void V102() { int domainWidth; int domainHeght; int domainDepth; if (IsX64Platform()) { domainWidth = 2000; domainHeght = 2000; domainDepth = 2000; } else { domainWidth = 500; domainHeght = 500;
  • 4. domainDepth = 500; } char *buffer = new char [size_t(domainWidth) * size_t(domainHeght) * size_t(domainDepth)]; char *current = buffer; char *end = buffer; end += domainWidth * domainHeght * domainDepth; while (current != end) *current++ = 1; delete [] buffer; } void V103() { size_t Megabyte = 1048576; size_t Gigabyte = 1073741824; size_t n = IsX64Platform() ? Gigabyte : Megabyte; unsigned arraySize = n * sizeof(INT_PTR); INT_PTR *buffer = (INT_PTR *)malloc(size_t(arraySize)); for (size_t i = 0; i != n; ++i) buffer[i] = 0; free(buffer); } void V104() { volatile size_t n; if (IsX64Platform()) { n = SafeMul(5, 1024, 1024, 1024);
  • 5. } else { n = SafeMul(5, 1024, 1024); } char *buffer = new char [n]; volatile size_t index = 0; volatile unsigned i; for (i = 0; i != n; ++i) buffer[index++] = 1; delete [] buffer; } void V105() { bool flag = true; unsigned a = unsigned(-1); if ((flag ? a : sizeof(float)) != size_t(-1)) { throw CString("x64 portability issues"); } } void V106() { void *buffer; const unsigned Megabyte = 1024 * 1024; const unsigned Gigabyte = 1024 * 1024 * 1024; unsigned unit; if (IsX64Platform()) unit = Gigabyte; else unit = Megabyte;
  • 6. buffer = malloc(5 * unit); if (IsX64Platform()) memset(buffer, 0, SafeMul(5, 1024, 1024, 1024)); else memset(buffer, 0, SafeMul(5, 1024, 1024)); free(buffer); } void V107_FillFunction(char *array, unsigned arraySize) { for (unsigned i = 0; i != arraySize; ++i) array[i] = 1; } void V107() { size_t n; if (IsX64Platform()) { n = SafeMul(5, 1024, 1024, 1024); } else { n = SafeMul(5, 1024, 1024); } char *array = (char *)malloc(n * sizeof(char)); memset(array, 0, n * sizeof(char)); V107_FillFunction(array, n); for (size_t i = 0; i != n; ++i) if (array[i] != 1) throw CString("x64 portability issues"); free(array); } void V108() { size_t n;
  • 7. if (IsX64Platform()) { n = SafeMul(5, 1024, 1024, 1024); } else { n = SafeMul(5, 1024, 1024); } char *array = (char *)malloc(n * sizeof(char)); memset(array, 0, n * sizeof(char)); volatile int index = 0; for (size_t i = 0; i != n; ++i) { array[index++] = 1; if (array[i] != 1) throw CString("x64 portability issues"); } free(array); } ptrdiff_t UnsafeCalcIndex(int x, int y, int width) { volatile int result = x + y * width; return result; } void V109() { int domainWidth; int domainHeght; if (IsX64Platform()) { domainWidth = 50000; domainHeght = 50000; } else { domainWidth = 5000; domainHeght = 5000; }
  • 8. char *array = (char *)malloc(SafeMul(domainWidth, domainHeght)); for (int x = 0; x != domainWidth; ++x) for (int y = 0; y != domainHeght; ++y) { array[UnsafeCalcIndex(x, y, domainWidth)] = 55; } free(array); } int UnsafeStrLen(const char *text) { const char *ptr = text; while (*ptr != 0) ++ptr; return ptr - text; } void V110() { size_t n; CString trueSize; if (IsX64Platform()) { n = SafeMul(3, 1024, 1024, 1024); trueSize = _T("3221225472"); } else { n = SafeMul(3, 1024, 1024); trueSize = _T("3145728"); } char *str = (char *)malloc(n * sizeof(char)); memset(str, 'V', n * sizeof(char)); str[n - 1] = 0; int len = UnsafeStrLen(str); CString falseSize; falseSize.Format(_T("%i"), len + 1);
  • 9. free(str); if (falseSize != trueSize) throw CString(_T("x64 portability issues")); } void V111() { char invalidStr[100], validStr[100]; const char *invalidFormat = "%u"; const char *validFormat = "%Iu"; size_t a = SIZE_MAX; sprintf_s(invalidStr, sizeof(invalidStr),invalidFormat, a); sprintf_s(validStr, sizeof(validStr), validFormat, a); if (strcmp(invalidStr, validStr) != 0) throw CString(_T("x64 portability issues")); } void V113() { size_t a = size_t(-1); double b = a; --a; --b; size_t c = b; if (a != c) throw CString(_T("x64 portability issues")); } void V114() { unsigned intPtr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; size_t *sizetPtr = (size_t *)(intPtr); size_t sum = 0;
  • 10. for (size_t i = 0; i != 10; ++i) sum += sizetPtr[i]; if (sum != 45) throw CString(_T("x64 portability issues")); } void V301() { class CWinAppTest { public: virtual void WinHelp(DWORD_PTR, UINT) { ::AfxMessageBox(_T("Cannot activate WinHelp")); } }; class CPortSampleApp : public CWinAppTest { public: virtual void WinHelp(DWORD, UINT) { ::AfxMessageBox(_T("WinHelp activated")); } }; CWinAppTest *Application = new CPortSampleApp(); Application->WinHelp(NULL, 0); delete Application; } int _tmain(int argc, TCHAR* argv[]) { V101(); V102(); V103(); V104(); V105();
  • 11. V106(); V107(); V108(); V109(); V110(); V111(); V112(); V113(); V114(); V201(); V202(); V203(); V301(); return 0; } Теперь, когда Вы увидели весь код, давайте рассмотрим все функции, содержащие ошибки. Когда мы говорим, что функции содержат ошибки, мы имеем в виду следующее. Представленный код прекрасно компилируется и работает в 32-битном режиме. Однако, после компиляции для 64- битного режима, работа программы становится некорректной, вплоть до падений. Неявное приведение к типу memsize void V101() { unsigned imageWidth = 1000; unsigned imageHeght = 1000; unsigned bytePerPixel = 3; unsigned maxFrameCountInBuffer; if (IsX64Platform()) { maxFrameCountInBuffer = 2000; } else { maxFrameCountInBuffer = 100; }
  • 12. size_t bufferSize = imageWidth * imageHeght * bytePerPixel * maxFrameCountInBuffer; BYTE *buffer = static_cast<BYTE *>(malloc(bufferSize)); BYTE *ptr = buffer; for (unsigned frame = 0; frame != maxFrameCountInBuffer; ++frame) for (unsigned width = 0; width != imageWidth; ++width) for (unsigned height = 0; height != imageHeght; ++height) { *ptr++ = 0xFF; *ptr++ = 0xFF; *ptr++ = 0x00; } free (buffer); } Проблема скрыта в следующей строке: size_t bufferSize = imageWidth * imageHeght * bytePerPixel * maxFrameCountInBuffer; Все переменные, участвующие в умножении, имеют тип unsigned, который и в 32-х и 64-битном режиме имеет размер 32 бита. Однако результат умножения записывается в переменную типа size_t, который в 32-битном режиме имеет размер, совпадающий с размером типа unsigned, а в 64-битном - не совпадающий. Но компилятор прекрасно выполняет расширение результирующего типа до unsigned. Казалось бы, проблемы нет? Есть! Если в результате умножения результат превысит 4 гигабайта, то переполнение произойдет и результат будет неверным. Использование не memsize-типа для арифметики с указателями void V102() { int domainWidth; int domainHeght; int domainDepth; if (IsX64Platform()) { domainWidth = 2000; domainHeght = 2000;
  • 13. domainDepth = 2000; } else { domainWidth = 500; domainHeght = 500; domainDepth = 500; } char *buffer = new char [size_t(domainWidth) * size_t(domainHeght) * size_t(domainDepth)]; char *current = buffer; char *end = buffer; end += domainWidth * domainHeght * domainDepth; while (current != end) *current++ = 1; delete [] buffer; } Проблема в данном коде заключается в арифметике с указателями, точнее в использовании для этой арифметики не memsize-типов: end += domainWidth * domainHeght * domainDepth; Ошибка в том, что на 64-битной платформе указатель end никогда не получит приращение более 4 гигабайт. Неявное приведение memsize-типа void V103() { size_t Megabyte = 1048576; size_t Gigabyte = 1073741824; size_t n = IsX64Platform() ? Gigabyte : Megabyte; unsigned arraySize = n * sizeof(INT_PTR); INT_PTR *buffer = (INT_PTR *)malloc(size_t(arraySize));
  • 14. for (size_t i = 0; i != n; ++i) buffer[i] = 0; free(buffer); } В следующем фрагменте кода присутствует совершенно очевидная ошибка: unsigned arraySize = n * sizeof(INT_PTR); Это неявное приведение к unsigned-типу переменной большей разрядности (на 64-битной платформе). Неявное приведение к memsize-типу в арифметическом выражении void V104() { volatile size_t n; if (IsX64Platform()) { n = SafeMul(5, 1024, 1024, 1024); } else { n = SafeMul(5, 1024, 1024); } char *buffer = new char [n]; volatile size_t index = 0; volatile unsigned i; for (i = 0; i != n; ++i) buffer[index++] = 1; delete [] buffer; } Операции вроде сравнения двух переменных, как ни странно, также могут стать источником проблем. В следующей строке: for (i = 0; i != n; ++i)
  • 15. проблема в том, что переменная i типа unsigned сравнивается с переменной n типа size_t, после чего происходит ее увеличение. Однако из-за того, что unsigned никогда не превышает 4 гигабайт, то переменная i никогда не будет больше этого значения. Что мы имеем в результате? Бесконечный цикл, так как условие i != n будет выполняться всегда. Неявное приведение к memsize типу в операции ?: void V105() { bool flag = true; unsigned a = unsigned(-1); if ((flag ? a : sizeof(float)) != size_t(-1)) { throw CString("x64 portability issues"); } } Этот пример очень похож на предыдущий. Проблема в следующей строке: if ((flag ? a : sizeof(float)) != size_t(-1)) { Здесь переменная a имеет тип unsigned, который при сравнении с size_t может дать некорректный результат. Почему? Да потому, что unsigned(-1) - это не тоже самое, что size_t (-1). Неявное приведение аргумента функции к memsize-типу. void V106() { void *buffer; const unsigned Megabyte = 1024 * 1024; const unsigned Gigabyte = 1024 * 1024 * 1024; unsigned unit; if (IsX64Platform()) unit = Gigabyte; else unit = Megabyte; buffer = malloc(5 * unit); if (IsX64Platform()) memset(buffer, 0, SafeMul(5, 1024, 1024, 1024));
  • 16. else memset(buffer, 0, SafeMul(5, 1024, 1024)); free(buffer); } В строке: buffer = malloc(5 * unit); программист рассчитывал получить на 64-битной системе буфер из 5 гигабайт. Однако здесь произойдет ошибка. Почему? Функция malloc() принимает аргумент memsize-типа и 5 гигабайт - вполне подходящее число. Однако при умножении (5 * unit) произойдет переполнение, т.к. переменная unit имеет тип unsigned. В результате получится вовсе не 5 гигабайт. Неявное приведение аргумента функции memsize-типа к 32- битному типу void V107_FillFunction(char *array, unsigned arraySize) { for (unsigned i = 0; i != arraySize; ++i) array[i] = 1; } void V107() { size_t n; if (IsX64Platform()) { n = SafeMul(5, 1024, 1024, 1024); } else { n = SafeMul(5, 1024, 1024); } char *array = (char *)malloc(n * sizeof(char)); memset(array, 0, n * sizeof(char)); V107_FillFunction(array, n); for (size_t i = 0; i != n; ++i) if (array[i] != 1) throw CString("x64 portability issues"); free(array);
  • 17. } В строке, с вызовом функции V107_FillFunction(array, n); происходит приведение типа переменной n к unsigned. Это означает усечение значения переменной, в результате чего может быть заполнен не весь массив. Использование для индексации некорректных типов void V108() { size_t n; if (IsX64Platform()) { n = SafeMul(5, 1024, 1024, 1024); } else { n = SafeMul(5, 1024, 1024); } char *array = (char *)malloc(n * sizeof(char)); memset(array, 0, n * sizeof(char)); volatile int index = 0; for (size_t i = 0; i != n; ++i) { array[index++] = 1; if (array[i] != 1) throw CString("x64 portability issues"); } free(array); } Если для индексации массива использовать не memsize-тип, то может произойти ошибка вида: array[index++] = 1; Проблема состоит в том, что в случае если в массиве присутствует более 4 гигабайт элементов, то обратится к ним с помощью переменной типа unsigned будет невозможно.
  • 18. Приведение к memsize-типу при использовании возвращаемого значения ptrdiff_t UnsafeCalcIndex(int x, int y, int width) { volatile int result = x + y * width; return result; } void V109() { int domainWidth; int domainHeght; if (IsX64Platform()) { domainWidth = 50000; domainHeght = 50000; } else { domainWidth = 5000; domainHeght = 5000; } char *array = (char *)malloc(SafeMul(domainWidth, domainHeght)); for (int x = 0; x != domainWidth; ++x) for (int y = 0; y != domainHeght; ++y) { array[UnsafeCalcIndex(x, y, domainWidth)] = 55; } free(array); } Удивительно, но в данном примере ошибка содержится в строке: return result; Переменная result имеет тип int, который неявно будет расширен до ptrdiff_t. Однако функция UnsafeCalcIndex() никогда не сможет вернуть индекс элемента, следующего за 2 гигабайтами. Конечно, правильнее сказать, что ошибка в неудачно выбранном типе переменной result. Эта переменная в данном случае должна иметь тип ptrdiff_t.
  • 19. Приведение memsize-типа при использовании возвращаемого значения int UnsafeStrLen(const char *text) { const char *ptr = text; while (*ptr != 0) ++ptr; return ptr - text; } void V110() { size_t n; CString trueSize; if (IsX64Platform()) { n = SafeMul(3, 1024, 1024, 1024); trueSize = _T("3221225472"); } else { n = SafeMul(3, 1024, 1024); trueSize = _T("3145728"); } char *str = (char *)malloc(n * sizeof(char)); memset(str, 'V', n * sizeof(char)); str[n - 1] = 0; int len = UnsafeStrLen(str); CString falseSize; falseSize.Format(_T("%i"), len + 1); if (falseSize != trueSize) throw CString(_T("x64 portability issues")); } Ситуация повторяет предыдущий пример, ошибка опять в строке возврата значения: return ptr - text;
  • 20. Отличие лишь в том, что здесь выполняется приведение memsize типа к типу int. В результате размер буфера (из примера) никогда не сможет быть вычислен в случае, если он больше 2 гигабайт. Вызов функции с переменным числом аргументов с memsize- параметром void V111() { char invalidStr[100], validStr[100]; const char *invalidFormat = "%u"; const char *validFormat = "%Iu"; size_t a = SIZE_MAX; sprintf_s(invalidStr, sizeof(invalidStr),invalidFormat, a); sprintf_s(validStr, sizeof(validStr), validFormat, a); if (strcmp(invalidStr, validStr) != 0) throw CString(_T("x64 portability issues")); } Функции с переменным числом аргументов очень часто используются для форматирования и ввода/вывода текстовых строк. Некорректное задание строки формата может привести к неправильной работе: const char *invalidFormat = "%u"; sprintf_s(invalidStr, sizeof(invalidStr),invalidFormat, a); Строка формата в данном примере рассчитана на 32-битный режим работы и в 64-битном режиме приведет к неправильному выводу. Неявное приведение memsize-типа к double и наоборот void V113() { size_t a = size_t(-1); double b = a; --a; --b; size_t c = b;
  • 21. if (a != c) throw CString(_T("x64 portability issues")); } В представленном примере ошибки содержатся в строках: double b = a; и size_t c = b; Такое присваивание на 64-битных системах некорректно, так как может вызвать потерю точности. Явные приведения типов при работе с указателями void V114() { unsigned intPtr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; size_t *sizetPtr = (size_t *)(intPtr); size_t sum = 0; for (size_t i = 0; i != 10; ++i) sum += sizetPtr[i]; if (sum != 45) throw CString(_T("x64 portability issues")); } Язык Си++, являясь низкоуровневым языком, позволяет работать с памятью на уровне указателей. Явные приведения типов при использовании указателей являются опасными в любом случае, однако приведение memsize типов как показано в примере, вдвойне опаснее: size_t *sizetPtr = (size_t *)(intPtr); Все дело в разности размеров типов size_t и unsigned. Перекрытие виртуальных функций void V301() { class CWinAppTest { public: virtual void WinHelp(DWORD_PTR, UINT) {
  • 22. ::AfxMessageBox(_T("Cannot activate WinHelp")); } }; class CPortSampleApp : public CWinAppTest { public: virtual void WinHelp(DWORD, UINT) { ::AfxMessageBox(_T("WinHelp activated")); } }; CWinAppTest *Application = new CPortSampleApp(); Application->WinHelp(NULL, 0); delete Application; } Одна из самых забавных ошибок в Си++ приложениях, которая может проявиться на 64-битных системах, связана с виртуальными функциями. Обратите внимание на параметры виртуальных функций в примере выше. На 32-битной системе DWORD_PTR и DWORD совпадают, и получается перекрытая виртуальная функция, а на 64-битной - это две разных функции! В результате вызов функции WinHelp() из примера приведет к появлению сообщения "Cannot activate WinHelp". Вместо заключения Итак, мы перечислили основные ошибки в коде, которые проявляются при переносе приложений на 64-битные системы? Вы скажете, что многие из них надуманы? Кому, например, может понадобиться буфер в 5 гигабайт на Windows-системе? Может быть, в 2007 году, это еще и не столь актуально, хотя многие ресурсоемкие приложения уже могут использовать такой объем памяти. Однако посмотрим, будет ли востребована эта статья уже через пару лет. Кто знает, может быть именно Вы будете долго отлаживать ошибку, возникающую при выделении нескольких гигабайт памяти. Информация об авторе Евгений Рыжков, один из создателей статического анализатора кода Viva64 (www.Viva64.com), предназначенного для упрощения переноса приложений на 64-битные платформы. Исследует проблемы миграции 32-битных программных систем на 64-битные платформы.