Home > itblogs > /LARGEADDRESSAWARE может испортить вам весь день.

/LARGEADDRESSAWARE может испортить вам весь день.

March 6th, 2007

Только что потратил кучу времени на разборки с /LARGEADDRESSAWARE. Этот ключ используется для указания сборщику, что данный модуль (.exe или .dll) способен корректно обрабатывать адреса больше 2GB. Модули, помеченные подобным образом, могут быть загружены выше 2GB при условии, что система поддерживает увеличенное пользовательское адресное пространство. На данный момент это либо серверные версии Windows, сконфигурированные ключом /3GB в boot.ini, либо 64-х битные версии системы.

Про причины того, почему расширенное адресное пространство не включается для всех программ, хорошо написал Raymond Chen: Myth: The /3GB switch expands the user-mode address space of all programs. Дело как всегда в том, что слишком много приложений не будут работать в такой конфигурации – начинает буксовать арифметика указателей. Сегодняшний баг занёс ещё одну операцию в “черный” список.

Итак, какое значение будет присвоено переменной wide_ptr после инициализации (код компилируется для x86)?

PVOID ptr = (PVOID)0x87654321;
ULONGLONG wide_ptr = (ULONGLONG)ptr;

Ответ – 0xffffffff87654321! Очевидно, что проблема в расширении знака, однако это совсем не очевидно из данного отрывка кода. Чтобы результат получился верным, код нужно переписать вот так:

PVOID ptr = (PVOID)0x87654321;
ULONGLONG wide_ptr = (ULONGLONG)(ULONG_PTR)ptr;
  1. Wesha
    March 7th, 2007 at 09:10 | #1

    Я думаю, расстрелять надо того @удака, который н-дцать лет назад сделал указатели signed.

  2. Not a kernel guy
    March 7th, 2007 at 09:26 | #2

    Если б каждого такого расстреливать – сколько бы народу полегло! :-)

  3. Wesha
    March 7th, 2007 at 16:56 | #3

    А заодно еще и того, кто придумал иметь общий стек на адреса возврата и временные данные (и тем самым породил проблемы с переполнением буфера).
    Кстати, совершенно не понимаю, почему современные компилерам не делают раздельные стеки. Тем самым проблема переполнения решается на 95% простой перекомпиляцией программы.

  4. Not a kernel guy
    March 7th, 2007 at 17:22 | #4

     

    Кстати, совершенно не понимаю, почему современные компилерам не делают раздельные стеки.

    Подозреваю, что из-за проблем с совместимостью и производительностью:

    1. Поломаются все существующие средства отладки. Да и существующим API, тому же Win32, не поздоровится;
    2. Из-за раздельных стеков придется все время либо перегружать esp, либо выделять отдельный регистр для второго стека, либо эмулировать второй стек вручную. В любом случае получается медленно.
  5. Wesha
    March 9th, 2007 at 09:33 | #5

    У всех свои недостатки (с) Во-первых, как-то смешно говорить о десятке лишних инструкций на системный вызов при процессорах о трех гигагерцах, а во-вторых, раз программу все равно перекомпилировать, то вполне можно иметь #define SAFE_STACK, по которому системные вызовы и будут все понимать.

    По-моему, все же лучше слегка пожертвовать производительностью, чем потом закрывать туеву хучу дырок постфактум. Проверка длины буфера – это, похоже, sacred knowledge, известное в основном только нашим программерам.

    P.S. У твоего блога сносит крышу, если коммент содержит кавычки или апострофы. Которые еще и эскейпятся криво. Похоже, вы там чего-то намудрили с защитой от sql injection.

  6. Not a kernel guy
    March 9th, 2007 at 10:43 | #6

     

    Во-первых, как-то смешно говорить о десятке лишних инструкций на системный вызов при процессорах о трех гигагерцах

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

    По-моему, все же лучше слегка пожертвовать производительностью

    Скорее всего производительность не будет основной проблемой. Вот совместимость – это да. Она будет такой проблемой, что мало не покажеться. Хотя, если подумать, .NET (или Java), по сути, и является решением, которое как раз и родилось в результате попыток сделать компилируемый код безопаснее. Заодно и проблему совместимости обошли. :-)

    У твоего блога сносит крышу

    Значит пришла пора перейти на версию посвежее: http://trac.wordpress.org/ticket/2761. :-)

Comments are closed.