• Like
64-битная версия Loki
Upcoming SlideShare
Loading in...5
×

64-битная версия Loki

  • 313 views
Uploaded on

Статья представляет собой отчет о проверки библиотеки Loki на совместимость с 64-битными системами с помощью анализатора кода Viva64 компании ООО "СиПроВер". Содержатся рекомендации пользователям …

Статья представляет собой отчет о проверки библиотеки Loki на совместимость с 64-битными системами с помощью анализатора кода Viva64 компании ООО "СиПроВер". Содержатся рекомендации пользователям библиотеки. Статья будет полезна также пользователям других библиотек, построенных на шаблонах, так как раскрывает особенности анализа подобных библиотек.

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
313
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
2
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. 64-битная версия LokiАвторы: Евгений Рыжков, Андрей Карпов, Андрей Александреску, Питер Кюмель, Рич Спозато,Дата: 25.09.2009АннотацияСтатья представляет собой отчет о проверки библиотеки Loki на совместимость с 64-битнымисистемами с помощью анализатора кода Viva64 компании ООО "СиПроВер". Содержатсярекомендации пользователям библиотеки. Статья будет полезна также пользователям другихбиблиотек, построенных на шаблонах, так как раскрывает особенности анализа подобныхбиблиотек.ВведениеБиблиотека Loki разработана Андреем Александреску как часть книги "Современноепроектирование на С++: Обобщенное программирование и прикладные шаблоныпроектирования". Аннотация к книге гласит: "В книге изложена новая технологияпрограммирования, представляющая собой сплав обобщенного программирования,метапрограммирования шаблонов и объектно-ориентированного программирования на C++.Настраиваемые компоненты, созданные автором, высоко подняли уровень абстракции, наделивязык C++ чертами языка спецификации проектирования, сохранив всю его мощь ивыразительность".Компания ООО "СиПроВер", создающая анализатор кода Viva64 для разработки 64-битныхприложений, активно общается с авторами различных программных проектов. Однажды к намобратился Рич Спозато (Rich Sposato), один из администраторов проекта Loki, и попросилпроверить код библиотеки на предмет совместимости с 64-битными системами с помощьюнашего инструмента Viva64. Мы сразу же согласились. Ведь это не только возможность принестипользу сообществу разработчиков, но и настоящий "тест выносливости" для нашего анализаторакода Viva64. Всем известно, что библиотека Loki написана с применением самых современных имощных возможностей языка Си++. И если анализатор Viva64 справится с Loki, то и другие болеепростые проекты не вызовут никаких проблем.Надо заметить, что данная статья основана на версии Loki от мая 2009 года (новее, чемофициальная на тот момент версия Loki 0.1.7), поэтому в более новых версиях Loki указанныепроблемы будут устранены.Итак, мы скачали последнюю версию Loki из SVN-репозитория и приступили к работе.Сборка 64-битной Loki в Microsoft Visual Studio 2005Анализатор кода Viva64 интегрируется в среду разработки Microsoft Visual Studio, поэтомуразумно было собрать версию Loki именно для этой среды. В составе пакета Loki есть готовыефайлы решений для Visual Studio 2005 и Visual Studio 2008. Однако на момент мая 2009 года этирешения содержат лишь 32-битные конфигурации. Поэтому необходимо в Visual Studio создать
  • 2. конфигурации для платформы x64. Добавив нужные конфигурации можно запустить компиляцию64-битной версии.Библиотека Loki предназначена для работы на большом количестве различных платформ исобирается с помощью многих наиболее известных компиляторов. Именно поэтому 64-битнаяверсия Loki скомпилировалась практически сразу же. Из 20 проектов, входящих в решение, несобрался только один:========== Build: 19 succeeded, 1 failed, 0 up-to-date, 0 skipped==========Это был проект SafeFormat:16>------ Build started: Project: SafeFormat, Configuration: Debug x64------16>Compiling...16>main.cpp16>.main.cpp(255) : error C3066: there are multiple waysthat an object of this type can be called with these arguments16> ....includeloki/SafeFormat.h(109): could beLoki::PrintfState<Device,Char>&Loki::PrintfState<Device,Char>::operator ()(bool)...16> while trying to match the argument list (UInt)Текст ошибки несколько сокращен, поскольку полностью он займет целую страницу. Посмотримна код, который приводит к ошибке:void test_dword(){ typedef signed int Int; typedef unsigned int UInt; typedef signed long Long; typedef unsigned long ULong; Int i(0); UInt ui(0); Long l(0); ULong ul(0); Printf("%d")(i);
  • 3. Printf("%d")(ui); // Проблема в этой строке Printf("%d")(l); Printf("%d")(ul);}Printf - это функция, внутри которой используется макрос LOKI_PRINTF_STATE_FORWARD. Спомощью этого макроса задается ряд вспомогательных функций. В нем-то и кроется проблема.Внутри файла SafeFormat.h вместо следующего фрагмента:#if (defined(_WIN32) || defined(_WIN64)) LOKI_PRINTF_STATE_FORWARD(unsigned long)#elseнеобходимо написать так:#if (defined(_WIN32) || defined(_WIN64))#if (defined(_WIN64)) LOKI_PRINTF_STATE_FORWARD(unsigned int)#endif LOKI_PRINTF_STATE_FORWARD(unsigned long)#elseПосле этого исправления ошибка компиляции пропадет и все 20 проектов библиотекискомпилируются.Однако среди прочих диагностических сообщений (warnings) компилятора мы видим сообщение,касающееся 64-битного кода:2>.CachedFactoryTest.cpp(204) : warning C4267: argument :conversion from size_t to const int, possible loss of data2> .CachedFactoryTest.cpp(238) : see reference to functiontemplateinstantiation milliSec typicalUse<Cache>(Cache &,unsigned int,unsigned int,unsigned int) being compiled2> with2> [2> Cache=CRandomEvict2> ]
  • 4. 2> .CachedFactoryTest.cpp(252) : see reference to functiontemplateinstantiation void displayTypicalUse<CRandomEvict>(Cache &,unsigned int,unsigned int,unsigned int) being compiled2> with2> [2> Cache=CRandomEvict2> ]Это сообщение говорит о потенциально опасном преобразовании типа size_t внутри функцииtypicalUse() в файле CachedFactoryTest.cpp:// Registering objectsfor(size_t i=0;i<objectKind;i++) CC.Register(i, createProductNull);Граница цикла (переменная objectKind) представлена типом unsigned. Поэтому использовать длясчетчика цикла переменную типа size_t не имеет смысла. После исправления типа счетчика циклапроблема исчезнет: // Registering objectsfor(unsigned i=0;i<objectKind;i++) CC.Register(i, createProductNull);После этих небольших исправлений мы имеем 64-битную библиотеку, которая успешнокомпилируется и не выдает никаких диагностических сообщений (warnings) насчет 64-битности.Но насколько в действительности код библиотеки корректен? Это мы определим с помощьюнашего анализатора кода Viva64.Проверка 64-битной Loki с помощью Viva64Для того чтобы убедится в совместимости Loki с 64-битными системами, выполним анализ кода спомощью Viva64. Анализатор кода Viva64 предназначен для разработки новых 64-битныхприложений и для миграций существующих 32-битных на 64-битную платформу.Запуск Viva64 для анализа Loki выявил список из 89 потенциально-опасных синтаксическихконструкций. Это не значит, что в библиотеке Loki содержится 89 ошибок, связанных с 64-битнымкодом. Но все эти 89 мест должен просмотреть разработчик для того, чтобы понять,действительно ли там возможна ошибка или нет. Разумеется, мы проанализировали эти ошибки.1 Некорректно используемая константа LONG_MINНачнем с ошибки, связанной с некорректно используемой константой LONG_MIN в следующейфункции:
  • 5. char* RenderWithoutSign(LOKI_SAFEFORMAT_SIGNED_LONG n, char* bufLast, unsigned int base, bool uppercase)Она находится в файле SafeFormat.h. Проблема в строке:if (n != LONG_MIN) {Тип LOKI_SAFEFORMAT_SIGNED_LONG объявляется как тип, способный вмещать 64-битныезначения в 64-битной системе. В Unix-системах (с моделью данных LP64) для этого используют типlong. Но в 64-битных Windows-системах (модель данных LLP64) тип long остался 32-битным.Поэтому в Loki тип LOKI_SAFEFORMAT_SIGNED_LONG объявлен так:#if defined(_WIN32) || defined(_WIN64) #define LOKI_SAFEFORMAT_SIGNED_LONG intptr_t #define LOKI_SAFEFORMAT_UNSIGNED_LONG uintptr_t#else #define LOKI_SAFEFORMAT_SIGNED_LONG signed long #define LOKI_SAFEFORMAT_UNSIGNED_LONG unsigned long#endifПоскольку тип long в 64-битных Windows-системах остался 32-битным, то и константа LONG_MINзадает минимальное значение 32-битной переменной. А это значит, что ее использованиенекорректно при работе с 64-битными типами (в нашем случае с intptr_t). Решением будетиспользование собственной константы. Например, исправление может выглядеть так:#if defined(_WIN32) || defined(_WIN64)# define LOKI_SAFEFORMAT_SIGNED_LONG intptr_t#if defined(_WIN64)# define LOKI_SAFEFORMAT_SIGNED_LONG_MIN_VALUE LLONG_MIN# define LOKI_SAFEFORMAT_SIGNED_LONG_MAX_VALUE LLONG_MAX#else# define LOKI_SAFEFORMAT_SIGNED_LONG_MIN_VALUE LONG_MIN# define LOKI_SAFEFORMAT_SIGNED_LONG_MAX_VALUE LONG_MAX#endif...#else# define LOKI_SAFEFORMAT_SIGNED_LONG signed long# define LOKI_SAFEFORMAT_SIGNED_LONG_MIN_VALUE LONG_MIN
  • 6. # define LOKI_SAFEFORMAT_SIGNED_LONG_MAX_VALUE LONG_MAX...#endifИ, соответственно, строкуif (n != LONG_MIN) {надо заменить на строкуif (n != LOKI_SAFEFORMAT_SIGNED_LONG_MIN_VALUE) {К счастью и к похвале создателей библиотеки Loki это единственное место, которое заслуживаветисправления. Описанные далее замечания могут быть интересны, но не имеют важности.2 Некоторые виды магических чисел - ошибка или нет?Одной из проблем, выявляемой анализатором Viva64 являются магические числа. С точки зрениямиграции кода с 32-битной на 64-битную платформу есть ряд чисел, использование которыхнаиболее опасно. Возможно, где-то в коде программист рассчитывает на определенный размертипа данных, что может вызвать проблему. Те, кто смотрят на сообщения от анализаторов кода,часто жалуются на бессмысленность подобных сообщений. Действительно, какой смысл ругатьсяанализатору кода на число 4 в подобных строках:::Loki::ScopeGuard guard4 = ::Loki::MakeGuard( &HasFour, 1, 2, 3, 4 );::Loki::ScopeGuard guard5 = ::Loki::MakeGuard( &HasFive, 1, 2, 3, 4, 5);Но бывают такие конструкции, которые надо анализировать очень тщательно. Например, в файлеSafeFormatmain.cpp видим код:case X: // TestCase(formatSpec, RandomInt(-10000, 10000)); // dont test negative values on 64bit systems, because // snprintf does not support 64 Bit values TestCase(formatSpec, RandomInt( -10000 * (sizeof(size_t)>4 ? 0 : 1) , 10000)); break;case e:Конкретно в этом месте проблемы, конечно же, нет. Но диагностика магических чисел ванализаторе кода нужна именно для нахождения таких конструкций в коде.3 Прибавление int к указателю - потенциальная проблемаФайл flexsimplestringstorage.h содержит функцию:void resize(size_type newSize, E fill)
  • 7. { const int delta = int(newSize - size()); if (delta == 0) return; if (delta > 0) { if (newSize > capacity()) { reserve(newSize); } E* e = &*end(); flex_string_details::pod_fill(e, e + delta, fill); } pData_->pEnd_ = pData_->buffer_ + newSize;}Анализатор Viva64 сообщает о потенциальной проблеме здесь:flex_string_details::pod_fill(e, e + delta, fill);Недостаток кода заключается в том, что к указателю e прибавляется переменная delta типа int. Этопотенциальная проблема, так как функция pod_fill не сможет обрабатывать объем данных болеедвух гигабайт (INT_MAX символов). Конечно же, конкретно здесь ошибки, видимо, нет, посколькувряд ли бывают строки более двух гигабайт. Но лучше все-таки заменить тип переменной delta сint на ptrdiff_t:const ptrdiff_t delta = ptrdiff_t(newSize - size());4 Использование int для индексации массивов некорректноДля доступа к большим массивам данным (более INT_MAX элементов) надо использовать типыptrdiff_t или size_t. В файле SmallObjSmallObjBench.cpp присутсвует довольно большой макросLOKI_SMALLOBJ_BENCH_ARRAY, в котором работа с массивом ведется через индексацию по int.Хотя это лучше исправить, в данном месте это не является ошибкой.5 Правильные аргументы функцийВнутри файла CachedFactoryCachedFactoryTest.cpp объявлена функция:template< class Cache >milliSec typicalUse(Cache &CC, unsigned objectKind, unsigned maxObjectCount, unsigned maxIteration)
  • 8. Для параметра objectKind лучше использовать тип size_t. Но поскольку этот код относится ктестам, то какой-либо серьезного недостатка в этом нет.Библиотека Loki совместима с 64-битными системами - значитпрограмма, использующая ее также совместима?Все немногие обнаруженные проблемы библиотеки Loki, перечисленные ранее, легко исправимы.Значит ли это, что если в Loki нет никаких 64-битных проблем (а это именно так), то и приложение,использующее эту библиотеку, безопасно с точки зрения 64-битного кода? К сожалению нет!Все дело в том, что библиотека Loki крайне активно использует шаблоны. А когда анализатор кодаразбирает код шаблона, он не всегда может диагностировать проблему. Для полной уверенностианализатору необходимо выполнить инстанцирование шаблонных классов и функций.Приведем просто пример, не относящийся к библиотеке Loki. Анализатор Viva64 среди прочихпроблем в коде может обнаруживать неоптимальные структуры данных:template <class T>struct TClass{ int m_a; T m_b; int m_c;};Если здесь T имеет тип int, то структура оптимальна. Если же T имеет тип size_t, то структуразаймет 24 байта, вместо возможных 16 байтах. Тогда в случае большого количества подобныхобъектов лучше было бы переписать:template <class T>struct TClass{ T m_b; int m_a; int m_c;};Но проверить это анализатор может только выполнив инстанцирование шаблона. То есть имеялишь объявление класса в заголовке выявит проблему нельзя.Другой пример, опять же не относящийся к Loki, связанный с приведением типов:template<typename T1, typename T2>
  • 9. class TemplateClass{public: void test1() { m_a.m_value = m_b.m_value; // Есть ли здесь ошибка? }private: T1 m_a; T2 m_b;};В данном коде ошибка приведения типов может быть, а может и не быть, в зависимости от того, скакими параметрами будет выполнено инстанцирование шаблона TemplateClass. Толькоанализируя код функции, не выполняя инстанцирование, анализатор не может сообщить обошибке.Перечисленные два примера шаблонных классов не относятся к библиотеке Loki, однако важныдля понимания принципов работы анализаторов кода. Особенность шаблонных библиотек типаLoki заключается в том, что даже если библиотека полностью совместима с 64-битнымисистемами, это не значит что код, который ее использует, корректен. Это в корне меняет подход кверификации приложений. Если при работе с обычной (не шаблонной) библиотекой достаточнобыть уверенным, что библиотека корректна с точки зрения 64-бит для того, чтобы бытьуверенным в корректности всего приложения, то с шаблонными библиотеками такой уверенностиуже быть не может.Все это означает, что хотя библиотека Loki и не содержит проблем 64-битного кода,пользовательское приложение, которое ее использует должно быть дополнительно провереноанализатором кода на отсутствие подобных проблем. Ведь ошибки зависят от того, с какимипараметрами выполняется инстанцирование шаблонов.ВыводыПо результатам работы сотрудников компании ООО "СиПроВер" над проверкой на совместимостьс 64-бибтными системами библиотеки Loki сделаны следующие выводы:Библиотека полностью совместима с 64-битными системами и не содержит потенциальныхошибок. Указанные в данной статье ошибки, скорее всего, будут очень быстро исправлены.Анализатор кода Viva64, предназначенный для разработки новых 64-битных и миграции старых32-битных приложений показал себя очень хорошо при проверке сложного шаблонного кодабиблиотеки. Это говорит о высоком качестве анализатора кода.
  • 10. Хотя библиотека Loki и не содержит 64-битных проблем, они возможны в пользовательскихприложениях, использующих Loki. Поскольку конечный код зависит от того, с какимипараметрами инстанцировались шаблоны, то обязательно надо проверять пользовательскиеприложения анализатором кода. Только тогда можно быть уверенным в полной совместимостиприложения с 64-битными системами.БлагодарностьБлагодарим всех, кто принимал участие в анализе библиотеки Loki и в оценке этой работы вкоманде Loki: • Спасибо компании ООО "СиПроВер", которая проанализировала код библиотеки Loki и выполнила верификацию ее для работы в 64-битном режиме, в частности: Андрею Карпову и Евгению Рыжкову. • Спасибо команде Loki: Андрею Александреску, Питеру Кюмелю, Ричу Спозато за совместную работу над проверкой и редактированием статьи, а также ценные замечания. • Спасибо Ричу Спозато, за координирование всей работы.Библиографический список 1. Библиотека Loki. http://www.viva64.com/go.php?url=515. 2. Анализатор кода Viva64. http://www.viva64.com/viva64-tool.