Забуті проблеми розробки 64-бітних програм, Різне, Програмування, статті

Введення


Історія розвитку 64-бітних програмних систем не нова і становить уже більше десятиліття [1]. У 1991 році був випущений перші 64-бітний мікропроцесор MIPS R4000 [2, 3]. З тих пір в форумах і статтях виникали дискусії присвячені перенесенню програм на 64-бітові системи. Почалося обговорення проблем пов’язаних з розробкою 64-бітних програм на мові Сі. Обговорювалися питання, яка модель даних краще, що таке long long і багато іншого. Ось, наприклад, цікава добірка повідомлень [4] з новинної групи comp.lang.c, присвячена використанню типу long long у мові Сі, що в свою чергу було пов’язано з появою 64-бітових систем.



Одним з найбільш поширених і чутливих до зміни розмірності типів даних є мова Сі. Через його низькорівневих властивостей, слід постійно контролювати коректність програми на цьому мовою, яку переносять на нову платформу. Природно, що при появі 64-бітових систем розробники по всьому світу знову зіткнулися з завданнями забезпечення сумісності старого вихідного коду з новими системами. Одним з непрямих свідчень складності проблем міграції є велика кількість моделей даних, які постійно слід враховувати. Модель даних – це співвідношення розмірів базових типів в мові програмування. На малюнку 1 показані розмірність типів в різних моделях даних, на які ми надалі будемо посилатися.



Рисунок 1. Моделі даних.

Існуючі публікації та інструменти в сфері верифікації 64-бітних додатків


Звичайно, це був не перший етап зміни розрядності. Досить згадати перехід з 16-бітових систем на 32-бітові. Природно накопичений досвід надав свій позитивний вплив на етапі переходу на 64-бітові системи.


Але перехід на 64-бітові системи, мав свої нюанси, в результаті чого з’явилася серій досліджень і публікацій з цих питань, наприклад [5, 6, 7].


В основному авторами того часу, виділялися помилки, наступних типів:



  1. Упаковка покажчиків в типи меншої розмірності. Наприклад, приміщення покажчика в тип int на системі з моделлю даних LP64 призведе до обрізання значення покажчика і неможливості його використовувати в подальшому.
  2. Використання магічних констант. Небезпека полягає у використанні таких чисел як 4, 32, 0x80000000 і ряду інших замість спеціалізованих констант або використання оператора sizeof ().
  3. Некоректні операції зсуву, не враховують збільшення розмірності ряду типів.
  4. Використання некоректних об’єднань або структур без урахування вирівнювання на системах з різною розрядністю.
  5. Помилки роботи з бітовими полями.
  6. Некоректні арифметичні вирази. Приклад:




int x = 100000, y = 100000, z = 100000;
long long s = x * y * x;

Розглядалися і деякі інші більш рідкісні помилки, але основні перераховані в списку.


На основі проведених дослідження питання верифікації 64-бітного коду були запропоновані рішення, що забезпечують діагностику небезпечні конструкцій. Наприклад, таку перевірку реалізували в статичних аналізаторах Gimpel Software PC-Lint (www.gimpel.com) І Parasoft C + + test (www.parasoft.com).


Виникає питання, якщо 64-бітові системи існують так давно, існують статті, присвячені даній тематиці і навіть програмні інструменти забезпечує контроль небезпечних конструкцій в коді, так варто Чи повертатися до цього питання?


На жаль так – варто. Причиною служить прогрес, що відбувся за ці роки в області інформаційних технологій. А актуальність даного питання пов’язана з швидким поширенням 64-бітових версій операційної системи Windows.


Існуюча інформаційна підтримка та інструменти в галузі розробки 64-бітових технологій застаріли і потребують суттєвої переробки. Але Ви заперечите, що в Інтернеті можна знайти безліч сучасних статей (2005-2007р), присвячених питанням розробки 64-бітних додатків на мові Сі / Сі + +. На жаль, на практиці вони є не більш ніж переказом старих статей, стосовно до нової 64-бітної версії Windows, без урахування її специфіки та змін, що відбулися технологій.


Неосвітлені проблеми розробки 64-бітних програм


Але почнемо по порядку. Автори нових статей не враховують, величезний обсяг пам’яті, який став доступний сучасним програмам. Звичайно, покажчики були 64-бітними ще в стародавні часи, але от використовувати таким програмам масиви розміром в кілька гігабайт не доводилося. В результаті, як в старих, так і в нових статтях випав цілий пласт помилок, пов’язаний з помилками індексації великих масивів. Практично неможливо знайти в статтях опис помилки, подібної наступною:





for (int x = 0; x != width; ++x)
for (int y = 0; y != height; ++y)
for (int z = 0; z != depth; ++z)
BigArray[z * width * height + y * width + x] = InitValue;

У цьому прикладі, вираз “z * width * height + y * width + x” використовується для адресації має тип int, А, отже, даний код буде некоректний на масивах, що містять більше 2 GB елементів. На 64-бітних системах для безпечної індексації до великих масивів слід використовувати типи ptrdiff_t, size_t або похідні від них. Відсутність опису такого виду помилки в статтях пояснюється дуже просто. За часів їх написання, машини з об’ємом пам’яті, що дозволяє зберігати такі масиви, були практично не доступні. Зараз же це стає рядовий завданням в програмуванні і з великим подивом можна спостерігати, як код вірою і правдою служив багато років, раптом перестає коректно працювати при роботі з великими масивами даних на 64-бітних системах.


Інший пласт практично неосвячені проблем, представлений помилками, пов’язаними з можливостями та особливостями мови Сі + +. Чому так сталося, теж досить зрозуміло. Під час впровадження перших 64-бітних систем, мова Сі + + для них не існував або він був не поширений. З цього практично всі статті присвячені проблемам в галузі мови Сі. Сучасні автори замінили назву Сі на Сі / Сі + +, але нового нічого не додали.


Але відсутність в статтях опису помилок специфічних для Сі + + не означає, що їх немає. Існують помилки, що проявляють себе при перенесенні програм на 64-бітові системи. Вони пов’язані з віртуальними функціями, винятками, перевантаженими функціями і так далі. Більш докладно з такими помилками можна ознайомитися в статті [8]. Наведемо простий приклад, пов’язаний з використанням віртуальних функцій.





сlass CWinApp {

virtual void WinHelp(DWORD_PTR dwData, UINT nCmd);
};
class CSampleApp : public CWinApp {

virtual void WinHelp(DWORD dwData, UINT nCmd);
};

Простежимо життєвий цикл розробки деякого програми. Нехай спочатку воно розроблялося під Microsoft Visual C + + 6.0. коли, функція WinHelp в класі CWinApp мала наступний прототип:





virtual void WinHelp(DWORD dwData, UINT nCmd = HELP_CONTEXT);

Абсолютно вірно було здійснити перекриття віртуальної функції в класі CSampleApp, як показано в прикладі. Потім проект був перенесений в Microsoft Visual C + + 2005 де прототип функції в класі CWinApp зазнав змін, які полягають у зміні типу DWORD на тип DWORD_PTR. На 32-бітної системі програма продовжить зовсім коректно працювати, так як тут типи DWORD і DWORD_PTR збігаються. Неприємності проявлять себе при компіляції даного коду під 64-бітну платформу. Вийдуть дві функції з однаковими іменами, але з різними параметрами, в результаті чого перестане викликатися користувальницький код.


Крім особливостей розробки 64-бітних програм з точки зору мови Сі + +, існують і інші тонкі моменти. Наприклад, особливості пов’язані з архітектурою 64-бітової версії Windows. Хочеться заздалегідь попередити розробників про потенційні проблеми і порекомендувати приділити більшу увагу тестуванню 64-бітного програмного забезпечення [9].


Тепер повернемося до методів верифікації вихідного коду програми з використанням статичних аналізаторів. Я думаю, ви вже вгадали, що тут теж не все так добре як здається. Не дивлячись на заявлену підтримку діагностування особливостей 64-бітного коду, ця підтримка на даний момент не задовольняє необхідною вимогою. Причина криється в тому, що діагностичні правила були створені за все тими ж статтями, не враховує специфіку мови Сі + + або обробку великих масивів даних, що перевищують 2 GB.


Для Windows розробників справи ще дещо гірше. Основні статичні аналізатори розраховані на діагностику 64-бітових помилок для моделі даних LP64, в той час, як в Windows використовується модель даних LLP64 [10]. Обумовлено це тим, що 64-бітні версії Windows молоді, а раніше 64-бітові системи були представлені Unix подібними системами з моделлю даних LP64.


Як приклад, розглянемо діагностичне повідомлення 3264bit_IntToLongPointerCast (port-10), що генерується аналізатором Parasoft C + + test.





int *intPointer;
long *longPointer;
longPointer = (long *)intPointer; //-ERR port-10

C + + test припускає, що з точки зору моделі LP64, дана конструкція буде некоректна. Але в рамках моделі даних прийнятих в Windows дана конструкція буде безпечна.


Рекомендації по верифікації 64-бітних програм


Добре, скажіть Ви, проблеми розробки 64-бітових версій програм дійсно актуальні. Але як знайти всі ці помилки?


Вичерпну відповідь дати не можна, але можна привести ряд рекомендацій, які в сумі дозволять забезпечити безпечну міграцію на 64-бітові системи і забезпечити необхідний рівень надійності.



Ресурси



  1. John R. Mashey, The Long Road to 64 Bits.
    www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=421&page=7
  2. Wikipedia: MIPS architecture.
    http://en.wikipedia.org/wiki/MIPS_architecture
  3. John R. Mashey, 64 bit processors: history and rationale.
    yarchive.net/comp/64bit.html
  4. John R. Mashey, The 64-bit integer type “long long”: arguments and history.
    yarchive.net/comp/longlong.html
  5. 64-bit and Data Size Neutrality.
    www.unix.org/whitepapers/64bit.html
  6. 64-Bit Programming Models: Why LP64?
    www.unix.org/version2/whatsnew/lp64_wp.html
  7. Transitioning C and C++ programs to the 64-bit data model.
    devresource.hp.com/drc/STK/docs/refs/64datamodel.jsp
  8. Andrey Karpov, Evgeniy Ryzhkov. 20 issues of porting C++ code on the 64-bit platform.
    www.viva64.com/articles/20_issues_of_porting_C++_code_on_the_64-bit_platform.html
  9. Andrey Karpov. Evgeniy Ryzhkov. Problems of testing 64-bit applications.
    www.viva64.com/articles/Problems_of_testing_64-bit_applications.html
  10. The Old New Thing: Why did the Win64 team choose the LLP64 model?
    blogs.msdn.com/oldnewthing/archive/2005/01/31/363790.aspx
  11. Brad Martin, Anita Rettinger, and Jasmit Singh. Multiplatform Porting to 64 Bits.
    www.ddj.com/hpc-high-performance-computing/184406427
  12. Migrating 32-bit Managed Code to 64-bit.
    msdn2.microsoft.com/en-us/library/ms973190.aspx
  13. Matt Pietrek. Everything You Need To Know To Start Programming 64-Bit Windows Systems.
    msdn.microsoft.com/msdnmag/issues/06/05/x64/default.aspx
  14. Microsoft Game Technology Group. 64-bit programming for Game Developers.
    msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/sixty_four_bit_programming_for_Game_Developers.asp
  15. John Paul Mueller. 24 Considerations for Moving Your Application to a 64-bit Platform.
    http://developer.amd.com/articlex.jsp?id=38
  16. Wikipedia: Static code analysis.
    http://en.wikipedia.org/wiki/Static_code_analysis
  17. Sergei Sokolov. Bulletproofing C++ Code.
    www.ddj.com/dept/debug/196802351
  18. Walter W. Schilling, Jr. and Mansoor Alam. Integrate Static Analysis Into a Software Development Process.
    www.ddj.com/dept/debug/193500967?cid=RSSfeed_DDJ_debugging
  19. Evgeniy Ryzhkov. Viva64: what is it and for whom is it meant?
    www.viva64.com/articles/Viva64_-_what_is_and_for.html

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*