![]() |
Ссылка в никуда или сломанный указатель.
Язык программирования C/C++ и ему подобные, можно по праву назвать «высокоуровневым ассемблером», благодаря их гибкости и свободе. Но у чрезмерной свободы существуют и свои недостатки, следует неустанно следить, за тем, чтобы свобода одного не мешала свободе другого. Именно поэтому на программистов «свободных»(C/C++/Assembler)языков ложится все бремя ответственности за правильный ход выполнения программы (в других языках программирования за многим следит компилятор и не позволяет программисту допускать ту или иную ошибку). Сегодня мы разберем уязвимости, к которым может привести неправильное использование указателей и ссылок. Указатель представляет из себя, адрес определенной переменной в памяти, на которую он указывает. Такой подход во многом упрощает программирования, экономит «такты процессора», позволяет более быстро обращаться к большим участкам памяти, без их копирования. Приведем пример на языке C с использованием указателей, да и перейдем сразу к делу:
Листинг программы на C Цитата:
Итак, по коду не сложно догадаться, что программа выведет в консоль число 25. Давайте скомпилируем данный пример, дабы убедиться в этом на практике. Представляю, как удивляться некоторые из вас, увидев, что p=10. Могу вас уверить, код выполнился, как ему и было положено, просто он содержит грубую ошибку, сейчас мы рассмотрим ее поподробнее. Для этого нам нужно забраться в самое сердце программы, взглянуть на нее в дизассемблированном виде. Код, который будет приведен ниже, немного исправлен мной, для лучшего понимания. Листинг дизассемблированной программы Цитата:
В данном примере все кроется в глобальных и локальных переменных. Глобальные переменные, это такие переменные которые «видны» всей программе сразу, к ним можно обратиться из любой функции или процедуры, они инициализируются при запуске программы. Локальные переменные, видны только той процедуре или функции, в которой они объявлены. Локальные переменные инициализируются при запуске той или иной функции, место для них выделяется в стеке: Код:
PUSH EBPКод:
MOV ESP,EBPТаким образом, мы и получили, в итоге 10. Такого рода ошибка, называется Висячим указателем. Висячий указатель - указатель, ссылающийся на уже удалённый объект. Чем чревата подобная ошибка, спросите вы? Первое, если бы я продолжал использовать (проводить арифметические и другие действия) над указателем на test, думая, что test у меня равна 25, то в итоге программа выдавала бы просто непредсказуемые результаты, вплоть до полного отказа ее работы. Второе, при выполнение некоторых условий, можно сознательно манипулировать значением переменной, а вдруг такая ошибка будет находиться в особо важном фрагменте кода, например в функции авторизации пользователя, а я смогу изменить значение ключевой переменной и авторизироваться без пароля! Замените функцию test2() на: Код:
int test2()Умный указатель— класс (обычно шаблонный), имитирующий интерфейс обычного указателя и добавляющий некую новую функциональность, например проверку границ при доступе или очистку памяти. Говоря попроще умный указатель, уничтожает сам себя, как только уничтожается объект, на который он указывает, что препятствует появлению висячих указателей. По мимо указателей существуют еще и понятие ссылки на объект. По своей сути они очень похожи на указатели, ссылка, можно сказать второе имя переменной(псевдоним), по которому к ней можно обращаться, но она не хранит адреса в отличие от указателя и считается более безопасной, но это не спасает ее от существования такого понятия, как висячие ссылки. А не спасает вот почему, ради чистого любопытства я решил проверить одну из своих догадок, и написал два экземпляра кода, с использованием указателей и ссылок: Листинг программы на C Цитата:
Скомпилировав, первый и второй варианты, затем дизассемблировав их, посмотрел, какой код выходит в итоге: Листинг дизассемблированной программы Цитата:
Причем в первом и втором случае ассемблерный код оказался совершенно одинаковым! Это говорит о том, что на низком уровне ссылки и указатели это одно и тоже. Отличия можно наблюдать лишь на высоком уровне, дело в том, что если вы попробуете использовать ссылку, как обычной указатель, то компилятор просто откажется компилировать, хотя на уровне ассемблерных команд реализация ссылок и указателей одинакова. Листинг неправильный код Цитата:
Я думаю именно потому, и существуют – «висячие ссылки». Нужно быть предельно осторожным при проектирование своих программ и особое внимание уделять указателям и ссылкам, ведь падение или неправильное выполнение программы еще не самое страшное, что может случиться, это еще одна, дополнительная лазейка для взломщика, которая может помочь ему в осуществление коварных планов. 13.11.2009 |
Зачем перенесли? это вроде, как статья.
|
Ух ты.. я читал про это на 2-ух сотой странице своей книги
|
Цитата:
Это совершенно разные языки, и в них общего почти ничего нет. |
Цитата:
|
я вот только не понимаю зачем так всё расписывать?
И так ясно что все локальные переменные расположены в стеке и следовательно верны до тех пор пока процедура / функция не завершит свою работу. Т.е. после завершения работы процедуры адрес остаётся валидным, но значение может быть уже любым. 2 nerezus ты так говоришь как будто сравниваешь ассемблер с бейсиком. в C И C++ очень много похожего. И практически всегда С программа может быть скомпилированная как С++. А вот С++ прога не всегда может компилиться как С Различия есть но не настолько уже и серьезные, если судить по синтаксису. |
Цитата:
|
Цитата:
Разного ГОРАЗДО больше, чем общего. Из общего ТОЛЬКО часть синтаксиса. |
А что, старый Borland Pascal или Delphi (и прочие алголоподобные языки) по мнению автора не поддерживают работу с указателями?
|
Поддерживают, но я не рассматривал их, у меня нет сомнений если бы я привел в статье пример для delphi или другого языка, то тут началась бы дискуссия, что мол автор сравнивает языки, что лучше делфи или си.
|
| Время: 15:19 |