Хроника одного бага.

October 3rd, 2007

Проект, над которым я работаю, предполагает довольно серьезные изменения некоторых компонентов системы, которые могут откликнуться проблемами с совместимости с существующими приложениями. В Microsoft-е совместимостью разве что малых детей не пугают, соответственно любое подобное изменение не обходится без внимания Application Compatibility team. В моем случае это означает, что я должен прогнать N-ое количество приложений через систему автоматических тестов и убедиться что все работает. И исправить если что-то не работает.

На прошлой неделе меня порадовал корейский MS Publisher 2000. После инсталляции, при каждом запуске появлялось окно Windows Installer, чего не наблюдалось на эталонной системе. Было похоже, что приложение безуспешно пытается установить какой-то отсутствующий компонент.

Хорошо. Запускаю приложение под отладчиком и останавливаю его в момент, когда появляется окно инсталлятора. В стеке – цепочка вызовов: mspub.exe -> … -> mso9.dll -> msi.dll. msi.dll это системная DLL, часть Windows Installer. mso9.dll – компонент MS Office и похоже, что интересующий меня кусок кода находится именно там. По крайней мере, функции из msi.dll похоже отвечают за установку features, что бы это не означало в данном конкретном случае. Проблема однако в том, что символы mso9.dll не доступны, а по куску из msi.dll не понятно, какая именно feature устанавливается.

Покопавшись во внутренней сети нашел как получить доступ к символам Office. Выясняется, что это может занять 6 и более часов. :-( Запрашиваю доступ и продолжаю коматься в отладчике без символов. В стеке выуживается строчка «UserData», которая, похоже, имеет непосредственное отношение к устанавливаемой feature. Поиск в реестре этой строчки находит много всего и ничего конкретного.

День второй.

На следующий день у меня уже есть доступ к хранилищу символов MS Office. Снова лезу в отладчик, но символы все равно не находятся. «.symopt+0×80000000» - выясняется, что нужных символов в хранилище похоже нет, так как моя mso9.dll была скомпилирована в 1999 году. Почесав затылок не придумал ничего лучше, как подменить mso9.dll версией на четыре года свежее. Как ни странно – заработало!

Вчерашняя догадка, что “UserData” – это название feature подтверждается, но что с этим знанием делать по-прежнему не понятно. Пробую декомпилировать .msi файл инсталляции. dark.exe из WiX, который был под рукой, не работает. Трачу еще полчаса на поиски Orca.

С его помощью по ключевой строке UserData нахожу путь “01:\Software\Microsoft\Office\9.0\UserData”. Проверяю – такого пути действительно нет (01 – это “HKEY_CURRENT_USER”) и Process Monitor показывает, что Publisher пытается открыть именно этот ключ. Тем не менее инсталлятор создавать этот ключ отказывается. Пробую несколько раз и наконец вижу, что нужный ключ создается, но создается он не в “HKEY_CURRENT_USER”, а в “HKEY_USER\.DEFAULT”!?

“HKEY_USER\.DEFAULT” – это “HKEY_CURRENT_USER” для учетной записи Local System. Это уже похоже на проблему с имперсонировнием учетных записей в msiexec.exe, который, в одном из своих воплощений запускается как служба под учетной записью Local System. Проблема только в том, что я не менял ничего, чтобы относилось к имперсонации.

Третий день.

Во время инсталляции процессы msiexec.exe плодятся как кролики. Определить какой из них создает ключ не всегда просто. Поэтому я просто добавляю код в NtCreateKey и NtOpenKey, который бросает отладочное исключение когда видит, что создается или открывается интересующий меня ключ. По ходу дела пишу письмо Руссиновичу – мол неплохо бы добавить в Process Monitor возможность генерировать отладочное исключение по нужному событию. На следующий день он отвечает – «да, неплохо бы, но ты один такой, кому это надо».

Запускаю инсталляцию и ловлю третий вызов NtOpenKey, как показал лог из Process Monitor. “!token” говорит, что текущий пользователь – Local System. «Ага!» – сказали сибирские мужики. «Фиг вам!» - ответила бензопила Дружба. Делаю тот же трюк на эталонной системе – текущий пользователь тоже Local Sуstem. Описатели ключей при этом по-прежнему показываю на разные ключи: “HKEY_CURRENT_USER” администратора и “HKEY_USER\.DEFAULT”.

Иду на поклон к гуру реестра. Он подсказывает, где псевдо описатели вроде “HKEY_CURRENT_USER” отображаются на настоящие описатели ключей. Ставлю точку останова по записи в переменную, где хранится описатель для “HKEY_CURRENT_USER”. Запускаю инсталляцию и ничего не происходит. Переключаюсь в ядерный отладчик, делаю это еще раз – и вижу где именно открывается этот описатель. На двух системах это происходит в совершенно разных местах и действительно, на эталонной системе msiexec.exe имперсонирует клиента, а на сбойной системе – нет.

Далее, ориентируясь на «правильный» стек, ставлю точку останова на том месте, где код сервиса получает RPC вызов от клиента запрашивающего инсталляцию. Фокус удаётся и дальнейшее дело техники. Просто трассирую код ориентируясь по эталонному стеку. Несколько раз промахиваюсь, но в конце концов нахожу проблемное место. Оказалось, что код отображения “HKEY_CURRENT_USER” на настоящий описатель проверял не имперсонирует ли текущий поток кого-либо и если это так, то полученный описатель не сохранялся в глобальной таблице. Вместо этого туда попадал описатель открытый сразу после вызова RevertToSelf, который как раз показывал на “HKEY_USER\.DEFAULT”.

Спрашиваю гуру что, мол, за дела? А он говорит, что да, помню было такое исправление, которое потом откатили назад, так как оно сломало множество приложений. А моя ветка создавалась именно в момент, когда это исправление еще не откатили…

Итог – две строчки кода равняются 24 часам отладки. :-)

Upd: Почему-то все решили, что баг был в Windows Installer. Это не так, баг сидел совсем в другом месте. Инсталлятор, как и любое другое приложение, просто вызывал этот код.

  1. October 3rd, 2007 at 22:29 | #1

    Что тут можно сказать - ужас!!!
    Если даже Вам требуется потратить столько сил на вылавливание блох при работе с Microsoft Installer, на что остаётся надеяться простым сисадминам и прикладникам, а ведь у них нет доступа к внутренней информационной базе майкрософта, спасибо хоть автору process monitor и прочих офигенно полезных sysinternals утилит,
    это просто ахтунг какой-то.

    • October 4th, 2007 at 08:51 | #2

      вылавливание блох при работе с Microsoft Installer

      Это не совсем верное утверждение. Windows Installer - это просто одно из приложений, которое среагировало на изменения в недрах системы. Точно также ведут себя приложения от других производителей софта. Тот же Acrobat Reader, Corel Draw и прочие.

      на что остаётся надеяться простым сисадминам и прикладникам

      Админам и прикладникам надо засыпать Microsoft толковыми багрепортами.

  2. Alexey.
    October 3rd, 2007 at 23:46 | #3

    Наконец то в микрософте стали наступать на те грабельки, которые щедро разбрасывали другим.
    И это прекрасно.
    Надеюсь, что ситуация с говноприложениями типа инсталера начнет когда-нить улучшаться (сам вспоминаю про собственный опыт работы с ним - с содроганием)

    • October 4th, 2007 at 08:52 | #4

      Не вижу причины для злорадства, откровенно говоря. Приложения, написанные не Microsoft, отлаживать ничуть не легче, и что?

      • October 4th, 2007 at 23:29 | #5

        Просто с мелкософт всё куда очевидней в виду распространенности. :)
        Да и есть, на кого ругаться: мелкософт. Плоды популярности…

      • Alexey.
        October 9th, 2007 at 00:36 | #7

        А кто сказал, что есть(была) альтернатива?
        Да и потом - вы согласны, что вин-инсталер - это гм… не очень профессионально написанное приложение?
        Просто с вашей, личной, точки зрения.

        • October 9th, 2007 at 11:02 | #8

          Я не вижу никаких особенных проблем с Windows Installer кроме:

          1. Он появился и развился до нормального уровня слишком поздно. В идеале версия 3.х должна была еще входить в состав Windows 95. :-)
          2. Документация написана бестолково. По крайней мере когда я её видел.
          3. Недостаток нормальных инструментов для создания инсталлация. Сравните WiX и все остальное . WiX на голову понятнее.
  3. dreamy_zombie
    October 4th, 2007 at 00:53 | #9

    Да импресонация в msi вещь. Тоже с этим боролись…

  4. October 4th, 2007 at 06:36 | #10

    Спасибо, было очень интересно почитать :)
    Напоминает “расследования” самого Руссиновича в его блоге, но, по-моему, у Вас покруче, чем его обычные посты .)

  5. October 5th, 2007 at 08:56 | #11

    Красотища! Спасибо, кстати, что рассказываешь такие вещи на русском языке — а то, все интересное — на английском. и е го не все читать умеют и любят :-)

    да и вообще, подобного рода рассказы до этого только у того же Руссиновича в блоге и видел :-)

  6. October 5th, 2007 at 10:20 | #12

    Админам и прикладникам надо засыпать Microsoft толковыми багрепортами.

    рассказали бы, как. а то помнится общались с вами зимой по поводу бага в hidparse.sys, связанного с usb клавами и залипанием ctrlbreak. с тех пор вышли sp2 для сервера, бетка sp3 для xp — ничего не изменилось. хотя тут злые языки утверждают, что hidparse само по себе один большой глюк, ms его купила у конторы, которой уже нет, а сама ms править боится, чтобы вообще всё работать не перестало.

    • October 5th, 2007 at 11:25 | #13

      Судя по комментариям в баге - у всех дел по горло и ошибка еще не исправлена. Чтобы предупредить возможные комментарии в духе “да там работы на полчаса” добавлю, что любое исправление требует значительных затрат на тестирование:

      • Либо его будут гонять специально по всем существующим тестам, чтобы убедиться что ничего не поломалось. Это в случае если исправление должно войти в состав сервис пака или заплатки;
      • Либо его оставят “варится” в текущей ветке, где ведется разработка, достаточно длительное время (минимум месяцы).

      Ну и понятное дело, что любая ошибка для которой есть workaround, которая не приводт к драматическим последствиям и которая была замечена спустя много лет, после выходя системы будет правиться в последнюю очередь.

      • October 5th, 2007 at 14:40 | #14

        добавлю, что любое исправление требует значительных затрат на тестирование

        лично мне хватило бы qfe хотфикса.

        Ну и понятное дело, что любая ошибка для которой есть workaround, которая не приводт к драматическим последствиям и которая была замечена спустя много лет

        вот даже и не знаю что сказать. ну вот написали бы вам в 2002 году, что в xp вдруг не стого перестаёт выполнять операции adobe photoshop, куда бы вы такого багрепортера послали? такой баг репорт на адобовском форуме кстати есть. а теперь, типа «спустя много лет». я комп год перегружал для запуска шопа. вы мне тут будете про «не приводт к драматическим последствиям» рассказывать? не приводит к драматическим последствиям он сейчас, когда я выполнил вашу работу по локализации причин. а нервы-то за год расшатались. не хочит ли майкрософт оплатить лечение у хорошего психотерапевта, а?

        • October 5th, 2007 at 16:58 | #15

          лично мне хватило бы qfe хотфикса.

          Выпуск QFE это очень дорогое (во всех отношениях) удовольствие.

          я комп год перегружал для запуска шопа. вы мне тут будете про «не приводт к драматическим последствиям» рассказывать? не приводит к драматическим последствиям он сейчас, когда я выполнил вашу работу по локализации причин. а нервы-то за год расшатались. не хочит ли майкрософт оплатить лечение у хорошего психотерапевта, а?

          Я могу лишь рассказать, почему исправление даже самой простой ошибки может занимать столько времени. Если вы хотите развить тему про то, что Microsoft должен и не должен - это не ко мне.

          • October 6th, 2007 at 04:21 | #16

            Выпуск QFE это очень дорогое (во всех отношениях) удовольствие.

            выложите исходники драйвера :)

            Я могу лишь рассказать, почему исправление даже самой простой ошибки может занимать столько времени.

            расскажите, будет полезно. конечно в общих чертах оно и так понятно, но конкретика будет как минимум интересна.

            Если вы хотите развить тему про то, что Microsoft должен и не должен - это не ко мне.

            это была ирония. на вот это:

            Админам и прикладникам надо засыпать Microsoft толковыми багрепортами.

            фраза не имеет смысла. потому как, если эти самые админы и прикладники не работают в крупном клиенте майкрософт, то багрепорт их исправят через пару лет, а обычно это нафиг уже не нужно. для крупных же клиентов толковость — пофиг, найдут и исправят всё равно.
            я-то в курсе, что майкрософт никому ничего не должен, только вот эта ваша фраза, даёт надежду на то, что мол если вот толковый баг репорт… зачем вообще такое писать?

            • October 6th, 2007 at 21:26 | #17

              фраза не имеет смысла. потому как, если эти самые админы и прикладники не работают в крупном клиенте майкрософт, то багрепорт их исправят через пару лет, а обычно это нафиг уже не нужно. для крупных же клиентов толковость — пофиг, найдут и исправят всё равно.

              Это отчасти верно, но не совсем. Скорость исправления ошибки напрямую зависит от потенциального количества её “жертв” и степени серьезности последствий. Если вы не крупный клиент, то ваш мелкий баг наверняка будет отложен до следующей версии ОС. Если этот баг затрагивает множество мелких клиентов, шансы на его скорое исправление возрастают многократно. Если это еще и дыра в безопасности, то шансы еще выше. «Толковость» баг репорта тут важна с той точки зрения, что по хорошему баг репорту гораздо легче понять серьезность и массовость бага.

              • October 7th, 2007 at 03:33 | #18

                Если это еще и дыра в безопасности, то шансы еще выше.

                это очевидно :)

                Если этот баг затрагивает множество мелких клиентов, шансы на его скорое исправление возрастают многократно.

                вот что-то сомневаюсь, что массовость можно вот так легко сходу определить. вот взять же тот самый баг с hidparse. я первоначально грешил на приложения, причём никак не связывал проблемы в двух разных приложениях. после локализации, я думал, что проблема в клавиатуре. и только протестировав ещё две модели добрался наконец до истинного виновника. а теперь вопрос, сколько пользователей отсеилось на первых двух шагах? про шоп я говорил уже, что один баг репорт я нашёл, и то чудом, потому как искать по «шоп иногда сходит с ума» дело неблагодарное. а вот с мирцем ситуация немного другая, сообщений о странном прерывании скриптов в гугле находится много. опять же далеко не факт, что эффект наблюдается только в этих двух приложениях. там массововость может быть любая. поэтому опять же честнее будет: «если вы докажете, что даже идииоту станет понятно, что этот баг затрагивает множество мелких клиентов, шансы на его скорое исправление возрастают многократно.»

                «Толковость» баг репорта тут важна с той точки зрения, что по хорошему баг репорту гораздо легче понять серьезность и массовость бага.

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

                • October 7th, 2007 at 10:40 | #19

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

                  Ошибка ошибке рознь.

  7. October 5th, 2007 at 22:33 | #20

    Уважаемый not-a-kernel-guy, не слушайте вы этих тролееподобных личностей :)
    По-моему объяснение исчерпывающее и понятное, кому-то просто хочется пофлудить.

    • October 6th, 2007 at 21:27 | #21

      Это ничего, главное чтобы сюда Neandertalets не заглянул. :-)

  1. October 3rd, 2007 at 21:35 | #1