pop-quiz: __try{} __harder{}

Тема в разделе "LANGS.C", создана пользователем catwalk_mission, 4 июн 2009.

  1. catwalk_mission

    catwalk_mission New Member

    Публикаций:
    0
    Регистрация:
    23 май 2009
    Сообщения:
    19
    вот есть небольшой исходник. желающих прошу попытаться определить, какое значение вернёт main, а также расставить цифры в прокомметированных местах, отмечая порядок их выполнения.
    пожалуйста, указывайте компилятор и (при необходимости) другие релевантные детали, из-за которых, по вашему мнению, код будет выполняться именно в указанном порядке.
    бонусный вопрос: а какой порядок выполнения можно считать корректным?

    Код (Text):
    1. #include <windows.h>
    2. #include <intrin.h>
    3.  
    4. #define int3() __debugbreak()
    5.  
    6. volatile int a, b;
    7.  
    8. int filter()
    9. {
    10.     if (b < 0x10) {
    11.         b += 0x10;             //
    12.         return EXCEPTION_CONTINUE_SEARCH;
    13.     }
    14.     if (b < 0x20) {
    15.         b += 0x20;             //
    16.         return EXCEPTION_EXECUTE_HANDLER;
    17.     }
    18.     b -= 0x10;                 //
    19.     return EXCEPTION_EXECUTE_HANDLER;
    20. }
    21.  
    22.  
    23. int main()
    24. {
    25.     a = 0;                     // 01
    26.     b = 0;
    27.  
    28.     __try {
    29.         a += 1;                // 02
    30.         __try {
    31.             a += 2;            // 03
    32.             __try {
    33.                 a += 4;        // 04
    34.                 __try {
    35.                     a += 8;    //
    36.                     int3();
    37.                 }
    38.                 __finally {
    39.                     a -= 8;    //
    40.                     int3();
    41.                 }
    42.                 b += 4;        //
    43.             }
    44.             __except(filter()) {
    45.                 a -= 4;        //
    46.             }
    47.             b += 2;            //
    48.         }
    49.         __finally {
    50.             a -= 2;            //
    51.         }
    52.         b += 1;                //
    53.     }
    54.     __except(filter()) {
    55.         a -= 1;                //
    56.     }
    57.  
    58.     return a + b;              //
    59. }
    то же с подсветкой
     
  2. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    catwalk_mission

    __try/__except/__finally это галимые микрософтные экстеншены, не имеющие никакого отношения к Стандарту. Так что все бонусные вопросы можно спустить в унитаз.
     
  3. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    По этой же причине компилятор можно не указывать :)
     
  4. catwalk_mission

    catwalk_mission New Member

    Публикаций:
    0
    Регистрация:
    23 май 2009
    Сообщения:
    19
    =P

    я не прошу это компилировать, кстати. просто приглашаю желающих подумать расставить с десяток чисел. компилятор попросил указывать только на случай варианта решения, несовпадающего с официальным мнением (т.е. с моим), но являющегося верным для какой-нибудь экзотической версии icc =)
    хотя... если ли смысл просить указывать компилятор в этом случае?.. в общем, как хотите =)
    но если что, будем разбираться, uguu~
     
  5. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    catwalk_mission
    в последнем _finally блоке a = 5, b = 32, считал в уме мог ошибица. Ответ стало быть 37.
    Кстати _DEN_ не совсем прав, экстеншены как он их назвал совсем не микрософные, а компиляторные (т.е. реализация поверх механизмов ОС (seh то бишь) зависит от данного конкретного компилятора.
     
  6. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Цифирки забыл написать:

    Код (Text):
    1. Код:
    2.  
    3. #include <windows.h>
    4. #include <intrin.h>
    5.  
    6. #define int3() __debugbreak()
    7.  
    8. volatile int a, b;
    9.  
    10. int filter()
    11. {
    12.     if (b < 0x10) {
    13.         b += 0x10;             // 06
    14.         return EXCEPTION_CONTINUE_SEARCH;
    15.     }
    16.     if (b < 0x20) {
    17.         b += 0x20;             // 07
    18.         return EXCEPTION_EXECUTE_HANDLER;
    19.     }
    20.     b -= 0x10;                 // 09
    21.     return EXCEPTION_EXECUTE_HANDLER;
    22. }
    23.  
    24.  
    25. int main()
    26. {
    27.     a = 0;                     // 01
    28.     b = 0;
    29.  
    30.     __try {
    31.         a += 1;                // 02
    32.         __try {
    33.             a += 2;            // 03
    34.             __try {
    35.                 a += 4;        // 04
    36.                 __try {
    37.                     a += 8;    // 05
    38.                     int3();
    39.                 }
    40.                 __finally {
    41.                     a -= 8;    //
    42.                     int3();
    43.                 }
    44.                 b += 4;        //
    45.             }
    46.             __except(filter()) {
    47.                 a -= 4;        //
    48.             }
    49.             b += 2;            //
    50.         }
    51.         __finally {
    52.             a -= 2;            // 10
    53.         }
    54.         b += 1;                //
    55.     }
    56.     __except(filter()) {
    57.         a -= 1;                //
    58.     }
    59.  
    60.     return a + b;              // 11
    61. }
     
  7. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    пропустил:

    Код (Text):
    1.  __finally {
    2.                     a -= 8;    // 08
    3.                     int3();
    4.                 }
     
  8. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    TSS

    Ну так студию вроде не 1C писали)) Ну пусть будут микрософтно-интелловские, делов-то. Основной смысл в том, что эта тема должна быть в WIN32, а никак не в LANG.C.
     
  9. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Согласен :)
     
  10. catwalk_mission

    catwalk_mission New Member

    Публикаций:
    0
    Регистрация:
    23 май 2009
    Сообщения:
    19
    ура-ура!
    первое решение есть. в настоящий момент собирается специальная комиссия, которая вынесет вердикт относительно представленного TSS варианта. возможно, в это время участники форума продемонстрируют другие решения?


    _DEN_
    wasm.win32? или wasm.x64?
    механизмы операционных систем, на которых базируется __try\__except (и try\catch), конечно, играют важнейшую роль, но в этой теме я бы хотел сделать упор на механизм __try\__except\__finally, обеспечиваемый именно компиляторами C\C++ (и прилагаемыми к ним библиотекам времени выполнения).
    если модераторы посчитают, что это всё же неподходящий раздел, то они перенесут тему... наверное =)
    кстати, _DEN_, не хотите попробовать? расставить циферки? ;)
     
  11. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    catwalk_mission

    try/throw/catch не имеет никакого отношения к механизмам операционной системы.


    Нет, не хочу. Я не знаток всяких там vendor-specified расширений и быть таковым не собираюсь. Встречный вопрос: не желаете придумать 5 аргументов "за" и 5 аргументов "против" того чтобы перегружать оператор "точка" в C++?
     
  12. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Проверил на MSVC2008 свое решение, оно неверное. Насколько я помню, по теории связанную цепочку seh винда пробегает дважды, во второй раз выполняя так называемый unwinding, и в этот момент должны вызываться finally обработчики, но они похоже вызываются дважы(почему компилятор так решил я незнаю). Вобщем согласен с _DEN_, задачка на знание механизмов ОС, равно как и задачка на знание чисто С++ исключений была бы более интересной, чем разбираться, почему один компилятор делает так, а другой по другому.
     
  13. Ursus

    Ursus Member

    Публикаций:
    0
    Регистрация:
    15 мар 2006
    Сообщения:
    238
    Адрес:
    Russia
    Да ну? А ничего, что, например в Win try/catch реализуется при помощи SEH?
     
  14. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    Ursus
    try/catch - присущ языку.
    вот именно. что в Win. под другими осями - может быть другая реализация.
     
  15. catwalk_mission

    catwalk_mission New Member

    Публикаций:
    0
    Регистрация:
    23 май 2009
    Сообщения:
    19
    ну что, за сутки всего одно решение? давайте поактивнее! первому приславшему правильный вариант будет выслана банка ништяков! =)

    _DEN_
    >Я не знаток всяких там vendor-specified расширений и быть таковым не собираюсь.
    ну как хотите. а ваш вопрос, к сожалению, к текущей теме не имеет никакого отношения – так что, пожалуй, как-нибудь в другой раз =P

    TSS
    да, неверное. ни с точки зрения теоретического стержня, который изначально закладывался в механизм __try\__except, ни с точки зрения его практической реализации в существующих системамах. сожалею. впрочем, по последнему вашему сообщению видно, что вы вплотную подошли к истине =)
     
  16. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    catwalk_mission
    С теорией касательно механизмов исключений(как высокоуровневых, так и на уровне ядра) у меня все в порядке, уверяю вас.

    И да, к сожалению, это ваш вопрос к текущей теме не имеет никакого отношения.
     
  17. catwalk_mission

    catwalk_mission New Member

    Публикаций:
    0
    Регистрация:
    23 май 2009
    Сообщения:
    19
    TSS получает бонус – приватное сообщение! =)
    найдутся ли желающие продемонстрировать верное решение?
     
  18. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    catwalk_mission
    Вот именно поэтому и возникают такие проблемы, что одна софтина тихо завершается, другая какието мессаги с ошибками боксит, третья всю систему за собой валакёт.. Не говоря уже про быстродействие и надёжность. Обработка исключения через полядра пройдёт, есчо и в юзермоде, стоит немного исказить стек как рухнет всё приложение. Структурная обработка ислючений разумеется весьма полезный механизм, но использовать его стоит только в критически важных местах, где например иного способа проверить валидность указателя нет и есть вероятность краха. Обычно оборачивается процедура один-два раза в сех-фреймы. И рантайм предоставляемый средой всеголишь обёртка вокруг тяжелого механизма исключений. Следует сделать упор на проверку валидности(на ноль не делить, указатели проверять и пр). Например принимает процедура указатель внутрь таблицы, следует проверить вхождение указателя в диапазон, а не расчитывать на то, что среда решит эту проблему сама.
     
  19. catwalk_mission

    catwalk_mission New Member

    Публикаций:
    0
    Регистрация:
    23 май 2009
    Сообщения:
    19
    по всей видимости задачка пооказалась большинству слишком простой и неинтересной. а ведь на самом деле всё не так просто, как можно подумать с первого взляда.
    итак, ответ, который можно считать правильным с точки зрения логики try\except\finally:
    Код (Text):
    1. #include <windows.h>
    2. #include <intrin.h>
    3.  
    4. #define int3() __debugbreak()
    5.  
    6. volatile int a, b;
    7.  
    8. int filter()
    9. {
    10.     if (b < 0x10) {
    11.         b += 0x10;             // 06: выполняем фильтр первый раз... возвращаем "продолжить поиск"...
    12.         return EXCEPTION_CONTINUE_SEARCH;
    13.     }
    14.     if (b < 0x20) {
    15.         b += 0x20;             // 07: выполняем фильтр второй раз... возвращаем "выполнить код в хендлере"
    16.                               //      но перед тем, как выполнится код в хендлере, должна быть проведена раскрутка.
    17.                               //      а поскольку раскрутка так и не будет доведена до конца, код в хендлере не выполнится...
    18.         return EXCEPTION_EXECUTE_HANDLER;
    19.     }
    20.     b -= 0x10;                 // 09: выполняем фильтр в третий раз... возвращаем "выполнить код в хендлере"
    21.                                //    (внимание: теперь мы готовимся выполнить код в другом хендлере)
    22.     return EXCEPTION_EXECUTE_HANDLER;
    23. }
    24.  
    25.  
    26. int main()
    27. {
    28.     a = 0;                     // 01
    29.     b = 0;
    30.  
    31.     __try {
    32.         a += 1;                // 02
    33.         __try {
    34.             a += 2;            // 03
    35.             __try {
    36.                 a += 4;        // 04
    37.                 __try {
    38.                     a += 8;    // 05
    39.                     int3();    //  исключение!
    40.                 }
    41.                 __finally {
    42.                     a -= 8;    // 08    выполняем раскрутку...
    43.                     int3();    //       исключение во время локальной раскрутки!
    44.                 }
    45.                 b += 4;        // -- этот код никогда не будет выполнен
    46.             }
    47.             __except(filter()) {
    48.                 a -= 4;        // 10    успешно выполняем код в хендлере и...
    49.             }
    50.             b += 2;            // 11    ...и продолжаем нормальное выполнение, как будто не было никаких исключений
    51.         }
    52.         __finally {
    53.             a -= 2;            // 12    выполняем finally (_не_ в рамках раскрутки)
    54.         }
    55.         b += 1;                // 13    нормальное выполнение продолжается
    56.     }
    57.     __except(filter()) {
    58.         a -= 1;                // --    этот код никогда не будет выполнен
    59.     }
    60.  
    61.     return a + b;              // 14    a == 1, b == 0x23.   return 0x24 == 36.
    62. }
    вероятно, большинство тех, кто размышлял над задачкой, представляли себе ход выполнения именно таким образом. однако, скомпилировав код с использованием стандартной CRT, они получили другой результат. а именно: 0x22 == 34.
    как верно было замечено TSS, один из блоков finally будет выполнен дважды. а именно – блок под номером 12: a -= 2.
    так что "альтернативно правильным" ответом можно считать 0x22 == 34. и, соответсвенно, вот циферки:
    Код (Text):
    1. #include <windows.h>
    2. #include <intrin.h>
    3.  
    4. #define int3() __debugbreak()
    5.  
    6. volatile int a, b;
    7.  
    8. int filter()
    9. {
    10.     if (b < 0x10) {
    11.         b += 0x10;             // 06: выполняем фильтр первый раз... возвращаем "продолжить поиск"...
    12.         return EXCEPTION_CONTINUE_SEARCH;
    13.     }
    14.     if (b < 0x20) {
    15.         b += 0x20;             // 07: выполняем фильтр второй раз... возвращаем "выполнить код в хендлере"
    16.                               //      но перед тем, как выполнится код в хендлере, должна быть проведена раскрутка.
    17.                               //      а поскольку раскрутка так и не будет доведена до конца, код в хендлере не выполнится...
    18.         return EXCEPTION_EXECUTE_HANDLER;
    19.     }
    20.     b -= 0x10;                 // 09: выполняем фильтр в третий раз... возвращаем "выполнить код в хендлере"
    21.                                //    (внимание: теперь мы готовимся выполнить код в другом хендлере)
    22.     return EXCEPTION_EXECUTE_HANDLER;
    23. }
    24.  
    25.  
    26. int main()
    27. {
    28.     a = 0;                     // 01
    29.     b = 0;
    30.  
    31.     __try {
    32.         a += 1;                // 02
    33.         __try {
    34.             a += 2;            // 03
    35.             __try {
    36.                 a += 4;        // 04
    37.                 __try {
    38.                     a += 8;    // 05
    39.                     int3();     //  исключение!
    40.                 }
    41.                 __finally {
    42.                     a -= 8;    // 08    выполняем раскрутку...
    43.                     int3();    //       исключение во время локальной раскрутки!
    44.                 }
    45.                 b += 4;        // -- этот код никогда не будет выполнен
    46.             }
    47.             __except(filter()) {
    48.                 a -= 4;        // 11    успешно выполняем код в хендлере и...
    49.             }
    50.             b += 2;            // 12    ...и продолжаем нормальное выполнение, как будто не было никаких исключений
    51.         }
    52.         __finally {
    53.             a -= 2;            // !! 10 (раскрутка? wtf?!)   // !! 13 выполняем finally (_не_ в рамках раскрутки)
    54.         }
    55.         b += 1;                // 14    нормальное выполнение продолжается
    56.     }
    57.     __except(filter()) {
    58.         a -= 1;                // --    этот код никогда не будет выполнен
    59.     }
    60.  
    61.     return a + b;              // 14    a == 0xFFFFFFFF, b == 0x23.   return 0x22 == 34.
    62. }
    причиной подобного поведения является ошибка в CRT. ошибка, должно быть, появилась весьма давно – неверный код присутвует даже в ntdll.dll от xp sp2.
    (кстати, в х64 всё в порядке, посколько аналогичный CRT-код попросту отсутствует за ненадобностью).

    да, функции с ошибкой – это '_unwind_handler4' и '_unwind_handler2'.

    надеюсь, кому-нибудь было интересно.
    будьте бдительны при обработке исключений! =)
     
  20. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Так а в чем конкретно заключается ошибка то? Где ресерч? )