Какое именно значение содержится в неинициализированной локальной переменной в C? - PullRequest
0 голосов
/ 03 октября 2018

Если у нас есть функция в C с простой унитарной переменной ìnt, мы знаем, что эта переменная не всегда может быть инициализирована нулем.Вместо этого он может содержать некоторое «мусорное» значение.

Мой вопрос: что именно может представлять это значение?Это может быть некоторая информация, оставленная (несвободная память) процессом, который был прерван раньше?

Если да, то не будет ли это серьезным нарушением безопасности?Потому что таким образом любой процесс может читать информацию, оставленную процессами, которые использовали то же адресное пространство, что и текущий процесс (пароли, токены и т. Д.).

Я предполагаю, что для каждого нового процесса ядро ​​обнуляетпамять, выделенная для этого нового процесса (по крайней мере, для стека), а затем он загружает исполняемый файл в память.Эти «мусорные» значения на самом деле являются значениями, сгенерированными процедурой загрузки текущего текущего процесса (так что нет никакого способа получить доступ к любым оставленным данным из других процессов, которые использовали то же адресное пространство).

Я спорю с некоторыми ребятами на эту тему и очень хочу получить четкий и исчерпывающий ответ на этот вопрос (я уверен, что он есть).Мы предполагаем, что ядро ​​основано на debian / centos.Было бы здорово узнать, есть ли различия в поведении для разных ядер / ОС.

С уважением.

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

Локальные переменные хранятся в пространстве стека, поэтому, как только вы завершите вызов текущей подпрограммы, указатель стека перемещается вверх, чтобы освободить все текущие локальные переменные подпрограммы, и по соображениям эффективности никакое предыдущее содержимое не удаляется (толькоуказатель стека перемещается).

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

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

Как эта памятьтеперь используется по-другому (как диктует локальное пространство текущей подпрограммы), нет правильной интерпретации такого содержимого памяти, но как удаляются данные из старого кода .

0 голосов
/ 03 октября 2018

Это должно быть разделено на два вопроса:

  • Что стандарт C говорит о значении неинициализированного объекта?
  • Что находится в памяти, когда вызывается main?

Первый вопрос обсуждается в других вопросах и ответах переполнения стека.Полный ответ сложен и включает в себя обсуждение различных обстоятельств, и этот вопрос, похоже, не задает этого вопроса, поэтому я оставлю его для других вопросов переполнения стека.Для этого вопроса достаточно сказать, что использование значения неинициализированного объекта подвержено неопределенному поведению.Кроме того, это не просто потому, что память объекта может иметь проблемные значения, а потому, что стандарт C позволяет реализации C обрабатывать программу, считывающую неинициализированное значение, как некорректно работающую программу различными способами, а оптимизация может затем нарушить работу программы..

Что касается того, что находится в памяти (предположим, у нас есть поддерживаемый способ проверить это, возможно, с использованием языка ассемблера вместо C), то каждая многопользовательская система, которая обеспечивает любые виды безопасности, стирает (илииначе инициализирует) память, прежде чем сделать ее доступной для процесса.Любые значения, которые находятся в памяти во время вызова main, являются, как предполагает вопрос, либо результатом процесса загрузки, либо инициализации операционной системой.(Обратите внимание, что результат процесса загрузки включает в себя как загрузку постоянных данных, так и текста программы - поэтому мы ожидаем найти там определенные значения - и любые данные, оставшиеся после работы, выполняемой кодом загрузки, - их переменные и так далее.)

Вопрос требует четкого ответа, поэтому позвольте мне прояснить это: операционная система, которая обеспечивает безопасность пользовательских процессов должна стереть данные предыдущих процессов из памяти перед созданием этой памятидоступны для другого процесса.Безопасность не может быть обеспечена , если доверять программе не проверять выделенную ей память и делать с ней все, что ей нужно.

Элементарные системы, не предназначенные для совместного использования ненадежными пользователями, могут, конечно, пропускатьинициализация памяти при создании новых процессов и выделении памяти для них.

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