Not a kernel guy

… in the Windows kernel team

Thursday, November 29, 2007

Говорила мне мама – сынок, проверяй результат каждой вызванной функции!

На днях в очередной раз попробовал поставить Punto Switcher после того, как на глаза попалась заметка о выходе версии, совместимой с Vista. Надо сказать, что я это делаю периодически, - в смысле устанавливаю Punto Switcher, играюсь с ним какое-то время, а потом удаляю. Честно говоря, я и сам не очень понимаю, почему он у меня не приживается. СОвсем неплохо напсаная программа. Какая-то тотальная несправедливость с моей стороны. Хотя нет, в последний раз причина была в том, что он не поддерживает 64-х битные версии Windows.

Но это неважно. Причиной написания этого поста стало то, что вскоре после установки Punto Switcher я заметил, что Notepad2 начал повисать в бесконечном цикле. Отладчик сразу подтвердил догадку о причастности Punto Switcher. Стек зависшего потока выглядел вот так:

correct.dll – это имя DLL которую Punto Switcher внедряет в каждый процесс для перехвата клавиатурного ввода. Оставалось ответить на два вопроса: «Почему Punto Switcher подвешивает только Notepad2?»и «Что такого делает Notepad2, что ломает Punto Switcher?»

Покопавшись в коде, выяснилось, что correct.dll на каждой итерации цикла функцию GetMenuItemInfo, каждый раз увеличивая номер элемента меню на единицу. Т.е. похоже, что correct.dll опрашивала все элементы меню.

На каждой итерации счетчик цикла (он же номер элемента меню, он же ebx) сравнивался с переменной, которая, по идее, должна была содержать общее число элементов меню. На самом деле переменная содержала 0xffffffff (-1).

Что характерно, функция возвращающая число элементов меню GetMenuItemCount возвращает -1 в случае ошибки. Догадка быстро подтвердилась в отладчике. GetMenuItemCount завершалась с ошибкой “1401: Invalid menu handle.”

Проблема, однако, заключалась в том, что описатель меню был самый, что ни на есть, правильный, что подтверждал Spy++, а функция GetMenu, возвращающая описатель, всегда завершалась успешно.

На следующий день, я попытался разобраться, что же не так с GetMenu и GetMenuItemCount. Долго ли, коротко ли, но в один прекрасный момент я заметил, что GetMenuItemCount работает, если функция вызывается из обработчика WM_CREATE главного окна Notepad2, и возвращает ошибку, если вызвать её позже. Оказалось, что всему виной были мои шаловливые ручки. Ранее, я добавил код для работы с меню в обработчик WM_CREATE. Этот код использовал класс CMenu из WTL. Объект этого класса предполагает, что он владеет описателем меню и, соответственно, удаляет его в своём деструкторе. GetMenu, естественно, об этом ничего не знает и по-прежнему возвращает теперь уже некорректный описатель.

Мораль этой истории – проверяйте результат каждой вызванной функции. Так как даже чужие ошибки (Notepad2) могут выглядеть как ваши собственные (Punto Switcher). Это особенно верно в случае, если код должен работать в «агрессивной среде» - DLL, внедряемая в чужой процесс, API операционной системы и так далее.

Posted at 10:03 pm •

RSS feed | Trackback URI

14 Comments »

[...] from blog.not-a-kernel-guy.com. Filed under: Debugging, [...]

 
Comment by Pavel — November 30, 2007 @ 1:46 am

Круто, впечатление такое - что только что я новую серию C.S.I. посмотрел =)

 
Comment by Alick — November 30, 2007 @ 2:43 am

Какая прелесть :-)

 
Comment by President — November 30, 2007 @ 3:43 am

Когда сообщите об этом авторам Punto Switcher?

Comment by Not a kernel guy — November 30, 2007 @ 8:24 am

Как только до почты доберусь. Вчера очень спать хотелось. :-)

Comment by Not a kernel guy — December 10, 2007 @ 8:02 pm

Что-то авторы молчат как рыба об лёд…

 
 
 
Comment by borat — November 30, 2007 @ 7:15 am

вы — зверь! :)))

очень позновательно :)

Comment by Not a kernel guy — November 30, 2007 @ 8:26 am

Настоящий зверь сидит здесь: Crash Dump Analysis. А я так, погулять вышел.

 
 
Comment by Volodymyr Shcherbyna — November 30, 2007 @ 8:53 am

Не согласен, предлагаю посмотреть http://blogs.technet.com/MarkRussinovich/

Comment by Volodymyr Shcherbyna — November 30, 2007 @ 8:56 am

Мой предыдущий пост относится к “Настоящий зверь сидит здесь: Crash Dump Analysis. А я так, погулять вышел.” :)

Comment by Not a kernel guy — November 30, 2007 @ 9:01 am

Руссинович, конечно, зверь, но у него куча других дел кроме отладки. Так что про отладку он как-то мало пишет в последнее время.

 
 
 
Pingback by Тут Хумора.NET — December 11, 2007 @ 5:00 am

[...] #337 Говорила мне мама – сынок, проверяй результат каждой в…! Небольшой рассказ о немного неаккуратном коде [...]

 
Comment by J()KER — January 30, 2008 @ 11:51 pm

Несколько не в тему - пользуюсь аналогом Keyboard Ninja с intelife.net/ninja/, так у него другой “глюк”: может в процессе работы сьедать 99% CPU ;-(

Comment by Not a kernel guy — January 31, 2008 @ 9:47 am

Если это завуалированное предложение “подебажить”, то нет, спасибо, что-то не хочеться. :-)

 
 

Your Comment (smaller | larger)

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by WordPress