Неинициализированная переменная - Uninitialized variable

В вычисление, неинициализированная переменная это Переменная который объявлен, но не имеет определенного известного значения перед его использованием. Это будет иметь немного значение, но не предсказуемое. Таким образом, это ошибка программирования и частый источник ошибки в программном обеспечении.

Пример языка C

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

Вот простой пример на C:

пустота считать( пустота ){    int k, я;        за (я = 0; я < 10; я++)    {        k = k + 1;    }        printf("% d", k);}

Окончательное значение k не определено. Ответ, что это должно быть 10, предполагает, что он начался с нуля, что может быть, а может и нет. Обратите внимание, что в примере переменная я инициализируется нулем первым предложением за утверждение.

Другой пример может быть при работе с структуры. Во фрагменте кода ниже у нас есть структурировать студента который содержит некоторые переменные, описывающие информацию об ученике. Функция register_student утечка памяти, потому что не может полностью инициализировать члены struct student new_student. Если мы посмотрим поближе, вначале возраст, семестр и Количество учащихся инициализированы. Но инициализация имя и фамилия члены неверны. Это потому, что если длина имя и фамилия массивы символов меньше 16 байт, во время strcpy, нам не удается полностью инициализировать все 16 байтов памяти, зарезервированных для каждого из этих членов. Следовательно, после memcpy ()преобразование полученной структуры в выход, мы передаем вызывающему объекту некоторую стековую память.

структура ученик {    беззнаковый int возраст;    беззнаковый int семестр;    char имя[16];    char фамилия[16];    беззнаковый int Количество учащихся;};int register_student(структура ученик *выход, int возраст, char *имя, char *фамилия){    // Если какой-либо из этих указателей равен нулю, мы терпим неудачу.    если (!выход || !имя || !фамилия)    {        printf("Ошибка! п");        возвращаться -1;    }    // Мы убеждаемся, что длина строк меньше 16 байтов (включая нулевой байт)    // во избежание переполнений    если (Strlen(имя) > 15 ||  Strlen(фамилия) > 15) {      printf("first_name и last_name не могут быть длиннее 16 символов! п");      возвращаться -1;    }    // Инициализация членов    структура ученик новый студент;    новый студент.возраст = возраст;    новый студент.семестр = 1;    новый студент.Количество учащихся = get_new_student_number();        strcpy(новый студент.имя, имя);    strcpy(новый студент.фамилия, фамилия);    // копируем результат в вывод    memcpy(выход, &новый студент, размер(структура ученик));    возвращаться 0;}


В любом случае, даже если переменная неявно инициализирован дефолт значение вроде 0, обычно это не правильный ценить. Инициализация не означает правильность, если значение установлено по умолчанию. (Однако инициализация по умолчанию 0 является правильной практикой для указателей и массивов указателей, поскольку она делает их недействительными до того, как они фактически инициализируются своим правильным значением.) В C переменные со статической продолжительностью хранения, которые не инициализированы явно, инициализируются как ноль (или ноль для указателей).[1]

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

Воздействия

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

Использование на языках

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

В других языках переменные часто инициализируются известными значениями при создании. Примеры включают:

  • VHDL инициализирует все стандартные переменные специальным значением «U». Он используется в моделировании для отладки, чтобы дать пользователю знать, когда все равно начальные значения, через многозначная логика, влияют на вывод.
  • Ява не имеет неинициализированных переменных. Поля классов и объектов, которые не имеют явного инициализатора, и элементы массивов автоматически инициализируются значением по умолчанию для их типа (false для логических значений, 0 для всех числовых типов, null для всех ссылочных типов).[2] Локальные переменные в Java должны быть определенно назначены до того, как к ним будет осуществлен доступ, в противном случае это ошибка компиляции.
  • Python инициализирует локальные переменные для НОЛЬ (в отличие от Никто) и вызывает UnboundLocalError когда к такой переменной обращаются до (пере) инициализации допустимым значением.
  • D инициализирует все переменные, если это явно не указано программистом.

Даже в языках, где разрешены неинициализированные переменные, многие компиляторы попытается идентифицировать использование неинициализированных переменных и сообщать о них как ошибки времени компиляции.

Смотрите также

Рекомендации

  1. ^ «ISO / IEC 9899: TC3 (текущий стандарт C)» (PDF). 2007-09-07. п. 126. Получено 2008-09-26.Раздел 6.7.8, параграф 10.
  2. ^ «Спецификация языка Java: 4.12.5 Начальные значения переменных». Sun Microsystems. Получено 2008-10-18.

дальнейшее чтение

  • CWE-457 Использование неинициализированной переменной [1].