«Безопасный» интервал значений указателя? - PullRequest
2 голосов
/ 18 июля 2011

Прежде всего, я не очень знаком со стеком и кучей.

Во многих программах я вижу, что указатели проверяются на NULL. Но это не мешает передать сумасшедший адрес, такой как 0x002011.

Мой вопрос: есть ли "безопасный" интервал адресов, к которому я могу проверить принадлежность указателя и быть разумно уверенным, что он действителен, перед разыменованием его?

Ответы [ 12 ]

8 голосов
/ 18 июля 2011

Нет.Обязательно инициализируйте указатели в NULL при создании новой переменной, а затем изменяйте значение только с помощью malloc (когда C) или new (когда C ++) или других функций выделения (или назначения другого допустимого указателя или NULL).Установите значение NULL после free и delete соответственно.

3 голосов
/ 18 июля 2011

NULL - это специальное значение, которое гарантированно является недопустимым указателем. Допустимо любое другое значение.

2 голосов
/ 19 июля 2011

Есть еще один случай, который не был рассмотрен здесь: написание библиотечной функции, где вы не можете контролировать передаваемые параметры и хотите, чтобы ваша функция возвращала ошибку типа «неверный указатель», а не сбой если используется указатель на неверный адрес.

Если это так, то я думаю, что есть специфичные для ОС функции, которые могут дать вам действительный диапазон адресов текущего процесса. Вам также нужно будет рассмотреть вопрос о том, является ли выравнивание адреса допустимым для передаваемого типа данных. Например, если 4-байтовое целочисленное значение может по закону находиться по нечетному адресу, где адрес% 4! = 0.

Обратите внимание, что даже если вы примете эти меры предосторожности, все равно нет гарантии, что вызывающая сторона не передаст законный указатель на недопустимые данные. Суть в том, что вы не можете исправить ошибку в вызывающем коде.

2 голосов
/ 18 июля 2011

Все, кроме NULL, которое исходит от malloc и друзей, является действительным указателем, однако сумасшедшая его ценность может показаться вам. Фактически, 0x002011 может быть совершенно корректным указателем на некоторых компьютерах (хотя, вероятно, не на современных настольных компьютерах).

И множество указателей на правильно выровненные, «вменяемые» адреса, которые все еще не принадлежат вашей программе. Если вы не оставляете указатели неинициализированными и не устанавливаете их вручную в значениях ерунды, единственный недействительный указатель, на который вам следует обратить внимание, это NULL. В качестве альтернативы, если это для библиотечного кода: не пытайтесь сделать это для своих пользователей, поскольку вы не можете (если вышеупомянутое не было достаточно явным), и в любом случае это их работа.

1 голос
/ 18 июля 2011

Указатель - это деталь реализации, а не контекстный тип. Следовательно, «допустимое значение указателя» не является универсальным свойством указателей; это свойство контекста, в котором используется указатель (или абстракция, которую представляет указатель). Например, указатель, указывающий на что-либо в стеке потока, не является допустимым указателем для передачи на free(...). Если вы можете выразить контекст, в котором указатель является действительным, то это просто вопрос перечисления или сопоставления со всеми указателями, действительными в этом контексте, чтобы определить, является ли указатель действительным (опять же, в этом контексте).

1 голос
/ 18 июля 2011

Нет, это не правильный способ делать вещи.

Вместо этого вы должны выяснить, почему эти сумасшедшие адреса передаются в первую очередь.Вы всегда должны либо передавать действительный указатель, который вы использовали для создания new или malloc (или какой-то другой вариант), либо вы должны передавать адрес выделенных объектов стека.

1 голос
/ 18 июля 2011

Нет, нет (портативного и надежного) способа определить, хорош ли указатель.

0 голосов
/ 20 июля 2011

Нет, для указателя любое значение, кроме нуля, может быть допустимым адресом.Поэтому традиционно программисты использовали NULL в качестве значения default invlaid для указателя.

Однако, если вы разрабатываете библиотеку, в которой вам нужна эта возможность, вы можете выполнить одно из следующих действий:

  1. Выделить память, необходимую для библиотеки в начале.(Предполагая, что вы знаете требование заранее).Используйте Custom Memory Manager, который будет использовать этот кусок памяти для обслуживания выделения памяти и освобождения запросов библиотекой.Любой адрес, который находится за пределами выделенной памяти ({начальный адрес, начальный адрес + размер}), является недопустимым указателем.

ИЛИ

  1. Разработка собственного диспетчера памяти, который отслеживаетблоков памяти, выделенных для разных модулей библиотеки.Чтобы проверить правильность указателя, он просматривает свою внутреннюю таблицу, чтобы увидеть, была ли выделена такая память или нет.

Примечание: Если проблема заключается в производительности, то вы можете запустить диспетчер памяти в двух режимах: выпуск и отладка.Чак дополнительная проверка в версии релиза.

Opencore (в Android) делает нечто похожее на второй подход.

Shash316

0 голосов
/ 19 июля 2011

В Windows вы можете попробовать использовать функцию VirtualQuery.Он принимает указатель ( lpAddress ), который вы хотите проверить, и возвращает информацию о странице, содержащей адрес, если он является действительным.

Если lpAddress указывает адрес выше самого высокого адреса памяти, доступного для процесса, функция завершается ошибкой с ERROR_INVALID_PARAMETER.

Этот вопрос может дать вам некоторую отправную точку в Linux: Есть ли лучший способчем разбирать / proc / self / maps для определения защиты памяти?

0 голосов
/ 19 июля 2011

Нет, и поэтому проверка указателей на NULL, кроме случаев, когда определено и задокументировано , что функция принимает NULL и придает ей особое значение, совершенно бессмысленно.C не позволяет писать функции, которые принимают указатели, но являются устойчивыми по отношению к вызывающей стороне, нарушающей контракт.Если вам это не нравится, либо не используйте указатели, либо не используйте C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...