Няшная / Говнокод #12540 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
long __stdcall wndproc(HWND wnd, unsigned int message, WPARAM wparam, LPARAM lparam)
{
	switch(message)
	{
	case WM_USER + 100:
		{
			char data[128];
			fill_data(data);
			PostMessage(wnd, WM_USER + 666,  0, (LPARAM)data);
			return 0;
		}
	case WM_USER + 666:
		{
			char * data = (char *)lparam;
			use_data(data);
			return 0;
		}
//etc

Wandering of the pointer или как выжить вне стека.

Запостил: Xom94ok Xom94ok, (Updated )

Комментарии (26) RSS

  • Если бы вместо PostMessage было SendMessage, ещё куда ни шло - просто wndproc вызвалась бы рекурсивно (хотя тоже не фонтан). А так между двумя циклами обработки сообщений стек затрётся.

    Кстати, на 64-битной архитектуре возвращаемое значение поплывёт - скажем спасибо MS за 32-битный long. Нельзя было объявить как LRESULT или тогда уж LONG_PTR?
    Ответить
    • >>скажем спасибо MS за 32-битный long
      Видимо, комплексы свои они так компенсируют; косвенно на это указывает псевдоним LONG, выглядящий "толще" обычного long-а.
      Ответить
      • Нет, это чтобы хомячкам не пришлось переписывать тонны ГК, написанного в предположении, что sizeof(int) == sizeof(long) == 4.
        Ответить
        • Угу, ещё надо вспомнить про то, что в DWORD помещается любой указатель
          Ответить
  • Есть всё написать определённым образом, то этот код будет стабильно работать.
    Ответить
      • Надо, чтобы при каждом вызове этой функции указатель на стек был один и тот же. Вроде бы это в винде выполняется, при условии, что функция зовётся виндой, а не прямо кодом пользователя через SendMessage.
        Ответить
          • я могу банально перед DispatchMessage() воткнуть alloca(rand())
            Ответить
                • Я много чего могу сделать, но мы обсуждаем, можно ли дописать остальную часть программы так, чтобы она стабильно работала, а не существование способа вставить в другое место кусок, который сделает её нерабочей. Вообще обсуждать второе бессмысленно, потому что это и так очевидно.
                  Ответить
                  • Да я на самом деле с тобой согласен. Должен быть контракт.
                    http://bit.ly/14RuoiA
                    А если соглашения нет, то порушить можно всё что угодно.
                    Ответить
                      • Допустим, он есть. Если его нету, то обсуждать что-либо неинтересно.
                        Я проверил, на WM_SIZE написал вывод в заголовок указателя на параметр Handle, при старте он не такой, как при работе, но во время работы он у меня не менялся.
                        Ответить
                          • точнее, понятно, почему не такой, не понятно, почему потом не меняется
                            Ответить
                            • А чё ему меняться? Напиши простую прогу на ВинАПИ, и внутри оконной функции посмотри стек.
                              Не такой он потому, что при первом вызове WM_SIZE (происходит при создании окна) на стеке отладчик видит только оконную функцию (видимо глубже там системные функции, которые он не различает), а при других WM_SIZE, инициированных пользователем, на стеке видно процедуру, в которой вызывается цикл обработки сообщений и 4 вызова оконной функции.
                              Ответить
                            • А почему потом не меняется, да потому что не с чему ему меняться, DispatchMessage вызывается в цикле каждый раз на одной глубине стека, а внутри него, скорее всего, делается тупо вызов оконной функции по указателю (с проверкой описателя и указателя, конечно), короче причин для разной вершины стека нету.
                              В общем, автор кода - очень везучий.
                              Ответить
                              • Да глубина тут вообще ни на что не влияет. В сообщении же передается указатель, поэтому даже при разных глубинах стека доступ будет к одному и тому же куску памяти. Другое дело - содержимое этого куска...

                                Если бы между приходами WM_USER+100 и WM_USER+666 закралось бы еще одно сообщение, то его обработчик вполне мог засрать область памяти, в которой лежала data, своими локальными переменными, и WM_USER+666 прочитал бы мусор.
                                Ответить
                                • Ну глубина влияет на то, что есть риск обратиться к памяти, лежащей на меньшей глубине в стеке, чем функция, и тем самым можно затереть адрес возврата например.
                                  Ответить
                              • Так и где гарантия, что DispatchMessage() будет всегда вызываться на одной глубине стека?
                                Ответить
                                • > на одной глубине стека
                                  Ну если память не изменяет - типичный цикл обработки сообщений выглядит так:
                                  while (GetMessage(&msg, 0, 0, ..)) {
                                      TranslateMessage(&msg);
                                      DispatchMessage(&msg);
                                  }
                                  Отсюда и гарантия одной глубины (но нет никакой гарантии, что тот же TranslateMessage или обработчики соседних сообщений не похерят данные в data).
                                  Ответить
                                • А что, где-то принято делать не так?
                                  Впрочем да, есть подвох в том, что можно вызвать ProcessMessages посреди сложного расчёта, но это не самый типичный случай.
                                  Ответить

Добавить комментарий

Из-за тебя ушел bormand, guest!

    А не использовать ли нам bbcode?


    8