| |||
![]()
|
![]() ![]() |
![]()
хардкор-программизм: как хороши, как свежи были розы... Функция IsBadReadPtr и прочие из той же группы очень давно мне не нравились. Ну хотя бы тем, что в данный момент такая функция может выдать тебе, что по данному адресу можно что-то читать, а уже через долю секунды другой тред как-нибудь перераспредилит память, и читать уже не получится. То есть, думал я, не лучше ли сразу читать проблемную память из под try-except блока, не заморачиваясь предварительными проверками? Реальность, однако, оказалась куда как хуже. Даже в чем-то безнадежной она оказалась. Выяснилось, что: если доступ к памяти "наугад", будь он сделан через IsBadReadPtr или же простое чтение памяти из-под try-except блока, нечаянно попадет на guard-страницу стека чужого треда, то guard-аттрибут этой страницы будет снесён, что впоследствии, когда стек второго треда подрастет за пределы той бывшей guard-страницы, приведет к "исчерпанию" стека этого треда и катастрофическому и молчаливому завершению всей аппликации. Конечно, при касании guard-страницы, кидается STATUS_GUARD_PAGE_VIOLATION исключение, и можно было бы попытаться восстановить аттрибут guard-страницы. Можно было бы, если бы не очевидный race-condition: пока мы будем восстанавливаеть аттрибут, второй тред уже может навернуться. Функция же IsBadReadPtr попросту ловит все исключения, и обрабатывает их единообразно, и не пытаясь восстанавливать какие-то там аттрибуты. И если бы только это... Выяснилось, что безотносительно вышеупомянутых бед, функция IsBadWritePtr еще и способна повреждать данные в мультитредной аппликации! А именно, чтобы проверить, можно ли записать данные, она их сначала читает, а потом уже пишет прочитанное значение по тому же самому адресу. Если между чтением и записью какой-то другой тред изменит значение данных, то это измененное значение будет немедленно затерто старым. Всё это, кстати, уже документировано на сайте msdn. |
||||||||||||||
![]() |
![]() |