Использование неинициализированной памяти c как исправить

Обновлено: 03.07.2024

В C++98 правильный способ получить неинициализированную память — использовать std::allocator::allocate/deallocate , IMO. В C++11 можно дополнительно использовать std::unique_ptr с автоматическим управлением.

Что такое неинициализированное чтение?

Использование неинициализированного чтения памяти приводит к ошибке выполнения чтения случайных данных. Обнаружение ошибки. Обычно среда IDE не обнаруживает ошибки такого типа; однако инструмент анализа памяти перехватывает условие чтения неинициализированных данных из недавно выделенной области памяти.

Каково значение неинициализированного указателя в C?

Нулевой указатель — это указатель, который ни на что не указывает. Нулевой указатель указывает на пустое место в памяти. Значение нулевого указателя равно 0. Мы можем сделать указатель так, чтобы он указывал на ноль, как показано ниже.

Что происходит, когда указатель не инициализирован?

Ссылка на нулевой указатель возникает всякий раз, когда указатель, указывающий на ноль, используется в операторе, пытающемся сослаться на блок. Например, если p — указатель на целое число, следующий код недействителен: p = 0; *р = 12; Однако разыменование такого указателя недопустимо.

Что использует неинициализированную память C++?

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

Что такое неинициализированная память?

Какая функция оставляет память неинициализированной?

14 ответов. calloc() дает буфер, инициализированный нулями, а malloc() оставляет память неинициализированной.

Почему моя программа использует неинициализированную память?

Пишу программу при изучении последовательного списка, теперь я хочу получить функцию поиска, но она постоянно говорит мне, что «Список» и «books_info» используют неинициализированную память. Я в замешательстве: я уже определил это в своей основной функции.

Как исправить неинициализированную память в Visual Studio?

Visual Studio выдает предупреждение C6001, когда неинициализированная локальная переменная используется до присвоения значения, что может привести к непредсказуемым результатам. Это предупреждение можно исправить, добавив пустые фигурные скобки, чтобы переменная/объект была инициализирована значением (будет содержать все нули).

Как использовать неинициализированную память в figher?

Прямо в «Fighter->viewStats();» это то место, где он говорит, что «использует неинициализированную память« Истребитель »». Я пробовал разные способы его инициализации, в том числе второй конструктор, который просто устанавливает все данные члена для «Fighter» в 0 или «none», просто чтобы там были значения. Что работало до того, как я изменил эту функцию (не функцию-член класса):

Когда использовать неинициализированные переменные в c6001?

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


Я работаю над консольной игрой, в которой вы играете за бойца, и недавно добавил функцию сохранения. После добавления этого и небольшого изменения одной из моих функций я получаю предупреждение об использовании неинициализированной памяти от IDE (C6001). Когда я пытаюсь скомпилировать, список ошибок не включает это предупреждение, но я предполагаю, что это предупреждение вызывает большинство ошибок, поскольку ни одна из них не имеет смысла, и IDE сходит с ума, когда я делаю то, что она говорит ( что-то вроде "Монстр;*"). Вот несколько фрагментов того, что происходит.

Прямо в "Fighter->viewStats();" это то место, где он говорит, что «использует неинициализированную память« Истребитель »». Я пробовал разные способы его инициализации, включая второй конструктор, который просто устанавливает все данные-члены для «Истребителя» в 0 или «нет», чтобы там были значения. Что работало до того, как я изменил эту функцию (не функцию-член класса):

Все, что я изменил здесь, это добавление параметра, чтобы я мог использовать уровень игрока, чтобы определить, с какими монстрами он, скорее всего, столкнется, и я добавил еще несколько монстров.


Я вижу такой путь в вашем коде, что вы никогда не создаете объект Character, и ваш указатель никогда не указывает на него.

если (выбор меню == 'l' )

Если ваш код вводит этот путь, то объект Character не создается, указатель остается указывать на произвольную память, и все плохо.


Персонаж* Боец; // Инициализировать указатель на новый объект класса "Fighter"
Это ничего не инициализирует. Здесь буквально ничего не инициализируется. Здесь не создаются объекты класса, этот указатель указывает на произвольную память.


Как я уже сказал, это работало до того, как я изменил функцию.

Итак, я восстановил конструктор по умолчанию при инициализации, переработал несколько моих s и изменил Fighter->viewStats(); в (*Fighter).viewStats(); , и я могу скомпилировать сейчас. В процессе я обнаружил, что причина, по которой он давал мне это предупреждение, заключается в том, что где-то там вызывался деструктор, вероятно, в одном из операторов if, поэтому, если я смогу найти и исправить это, это будет золото.< /p>


Как я уже сказал, это работало до того, как я изменил функцию.

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

Кроме того, в современном C++ новое — плохой знак. Необработанные указатели, как в этом коде, — плохой знак.


Хорошо, шаг за шагом.

Во-первых, я новичок в этом. Вы производите впечатление очень грубого, просто говорите мне, что я ошибаюсь или что это плохо, не предоставляя особого/какого-либо контекста. Часть проблемы заключалась в том, что возникла проблема с моим s, поэтому некоторые вещи не работали. Исправлено. Да, часть проблемы заключалась в том, что указатель на самом деле не был инициализирован, а просто объявлен. Исправлено это с помощью конструктора по умолчанию.

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

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

Спасибо, что нашли время просмотреть мой код и ответить на вопрос. Пожалуйста, предоставьте немного больше информации о том, что я могу улучшить.


Да, мы здесь очень кратки. Такова жизнь.

Видите ту строку, где вы используете указатель Fighter и записываете какие-то данные в какую-то память? Этот указатель указывает на случайную память, поэтому вы пишете по случайной памяти. Это плохо.

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

Хотя можно написать классы, которые могут существовать только в куче, я подозреваю, что вы этого не сделали. Так что это не имеет никакого смысла.

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

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


Да, это была проблема со сроком службы объекта. Я рассмотрю умные указатели.

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

Ошибки памяти очень часто возникают в приложениях C и C++ и могут повлиять на стабильность и правильность работы приложения. Эти ошибки возникают из-за программных ошибок. Их может быть трудно воспроизвести, трудно отладить, а также потенциально дорого исправить. Приложения, которые имеют ошибки памяти, могут столкнуться с серьезными проблемами. Например, утечка памяти может привести к нехватке памяти приложения, что приведет к завершению приложения, корректно или иным образом. Эта статья помогает разобраться в сложных ошибках памяти в последовательных/многопоточных приложениях и предоставляет помощь по использованию инструментов для поиска ошибок.

  • Неверный доступ к памяти в куче и стеке
  • Утечка памяти
  • Несоответствующее выделение/отмена
  • Отсутствует выделение
  • Неинициализированный доступ к памяти в куче и стеке
  • Доступ к нескольким стекам

Недопустимый доступ к памяти

Утечки памяти

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

Несоответствующее выделение/отмена

Эта ошибка возникает при попытке освобождения с помощью функции, которая не является логическим аналогом используемой функции распределения. Чтобы избежать несовпадения выделения/освобождения, убедитесь, что вызывается правильный освободитель. В C++ new[] используется для выделения памяти, а delete[] — для ее освобождения. В C функции malloc(), calloc() и realloc() используются для выделения памяти, а функция free() используется для освобождения выделенной памяти. Точно так же в программировании Windows есть API для выделения и освобождения памяти.

Отсутствует размещение

Эта ошибка возникает при освобождении памяти, которая уже была освобождена. Это также называется «повторным бесплатным» или «двойным бесплатным». Пример:

Неинициализированный доступ к памяти

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

Кросс-стек доступа

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

Использование инструментов для поиска ошибок памяти

На рынке доступно множество средств проверки ошибок памяти; Я использовал Intel Parallel Inspector для поиска ошибок памяти. Это простой и всеобъемлющий инструмент для точного определения ошибок памяти как в последовательных, так и в многопоточных приложениях.


Intel Parallel Inspector интегрируется в Visual Studio. Parallel Inspector использует динамические инструменты, не требующие специальных сборок или компиляторов. Не все средства проверки памяти, доступные на рынке, способны выполнять анализ многопоточных приложений. Как показано ниже, Parallel Inspector находит все типы ошибок памяти и отображает исходный код, модуль и номер строки исходного кода с состоянием ошибки (исправлено/не исправлено).

  • 2x-20x — анализ обнаруживает утечки памяти
  • 10 x–40 x – анализ выявляет наличие проблемы.
  • 20x-80x: анализ предоставляет информацию об основных причинах для устранения проблем и расширенной проверки оборванных указателей.
  • 40x-160x — обеспечивает наиболее полный уровень проблемы (включая проверку системных библиотек)


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

Заключение

Ручное обнаружение ошибок памяти очень сложно в больших приложениях. Использование правильного инструмента для их автоматического обнаружения очень поможет. Parallel Inspector — один из лучших инструментов для поиска ошибок памяти как в последовательных, так и в параллельных приложениях.

В коде используется переменная, которая не была инициализирована, что приводит к непредсказуемым или непредвиденным результатам.

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

В этой таблице показаны недостатки и категории высокого уровня, связанные с этим недостатком. Эти отношения определяются как ChildOf, ParentOf, MemberOf и дают представление об аналогичных элементах, которые могут существовать на более высоких и более низких уровнях абстракции. Кроме того, такие отношения, как PeerOf и CanAlsoBe, определены для выявления аналогичных недостатков, которые пользователь может захотеть изучить.

ПриродаТипIDИмя
ChildOf Base — слабость, которая по-прежнему в основном не зависит от ресурса или технологии, но с достаточными подробностями, чтобы предоставить конкретные методы обнаружения и предотвращения.Слабые места базового уровня обычно описывают проблемы с точки зрения 2 или 3 из следующих параметров: поведение, свойство, технология, язык и ресурс. 908Использование неинициализированного ресурса
CanFollow Вариант — слабость, связанная с определенным типом продукта, обычно связанная с определенным языком или технологией. Более специфична, чем базовая слабость. Слабые места на уровне вариантов обычно описывают проблемы с точки зрения 3–5 следующих аспектов: поведение, свойство, технология, язык и ресурс. 456Отсутствует инициализация переменной

В этой таблице показаны недостатки и категории высокого уровня, связанные с этим недостатком. Эти отношения определяются как ChildOf, ParentOf, MemberOf и дают представление об аналогичных элементах, которые могут существовать на более высоких и более низких уровнях абстракции. Кроме того, такие отношения, как PeerOf и CanAlsoBe, определены для выявления аналогичных недостатков, которые пользователь может захотеть изучить.

ПриродаТипIDИмя
ChildOf Класс — слабость, описанная в очень абстрактная мода, как правило, независимая от какого-либо конкретного языка или технологии. Более конкретный, чем Слабость Столпа, но более общий, чем Слабость Базы. Слабые места на уровне класса обычно описывают проблемы с точки зрения 1 или 2 из следующих параметров: поведение, свойство и ресурс. 665Неправильно Инициализация

В этой таблице показаны недостатки и категории высокого уровня, связанные с этим недостатком. Эти отношения определяются как ChildOf, ParentOf, MemberOf и дают представление об аналогичных элементах, которые могут существовать на более высоких и более низких уровнях абстракции. Кроме того, такие отношения, как PeerOf и CanAlsoBe, определены для выявления аналогичных недостатков, которые пользователь может захотеть изучить.

ПриродаТипIDИмя
ChildOf Класс — слабость, описанная в очень абстрактная мода, как правило, независимая от какого-либо конкретного языка или технологии. Более конкретный, чем Слабость Столпа, но более общий, чем Слабость Базы. Слабые места на уровне класса обычно описывают проблемы с точки зрения 1 или 2 из следующих параметров: поведение, свойство и ресурс. 665Неправильно Инициализация
Различные Способы внедрения предоставляют информацию о том, как и когда может быть введена эта слабость. Этап определяет точку жизненного цикла, в которой может произойти внедрение, а в примечании приводится типичный сценарий, связанный с внедрением на данном этапе.
ФазаПримечание
РеализацияВ C с использованием неинициализированного char * в некоторых библиотеках строк возвращаются неверные результаты, так как библиотеки ожидают, что нулевой терминатор всегда будет в конце строки, даже если строка пуста.

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

C (иногда встречается)

C++ (иногда распространен)

Perl (часто распространенный)

PHP (часто распространенный)

Класс: не зависящий от языка (неопределенная распространенность)

Технические последствия: Другое

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

Технические последствия: Другое

Неинициализированные строки особенно опасны, так как многие функции ожидают нулевое значение в конце — и только в конце — строки.

Этот код печатает приветствие, используя информацию, хранящуюся в запросе POST:

Этот код проверяет, заданы ли имена массива POST, прежде чем присваивать его переменной $nameArray. Однако, если массива нет в POST-запросе, $nameArray останется неинициализированным. Это вызовет ошибку при доступе к массиву для печати приветственного сообщения, что может привести к дальнейшему использованию.

Следующий оператор switch предназначен для установки значений переменных aN и bN перед их использованием:

В случае оператора switch по умолчанию программист случайно установил значение aN дважды. В результате bN будет иметь неопределенное значение. Большинство проблем с неинициализированными переменными приводят к общим проблемам с надежностью программного обеспечения, но если злоумышленники могут намеренно инициировать использование неинициализированных переменных, они могут запустить атаку типа «отказ в обслуживании» путем сбоя программы. При определенных обстоятельствах злоумышленник может контролировать значение неинициализированной переменной, изменяя значения в стеке до вызова функции.

В этом примере test_string останется в неизвестном состоянии, если i равно значению err_val, поскольку test_string не инициализирован (CWE-456). В зависимости от того, где появляется этот сегмент кода (например, в теле функции), test_string может быть случайным, если он хранится в куче или стеке. Если переменная объявлена ​​в статической памяти, она может быть нулевой или NULL. Оптимизация компилятора может способствовать непредсказуемости этого адреса.

При достижении функции printf() test_string может оказаться неожиданным адресом, поэтому функция printf может напечатать ненужные строки (CWE-457).

Чтобы исправить этот код, существует несколько подходов к проверке правильности установки test_string после достижения функции printf().

Одним из решений может быть установка для test_string приемлемого значения по умолчанию перед условием:

Другое решение состоит в том, чтобы гарантировать, что каждая ветвь условного оператора, включая ветвь default/else, может гарантировать, что test_string установлен:

Цепочка: вызов sscanf() используется для проверки существования имени пользователя и группы, но возвращаемое значение вызова sscanf() не проверяется (CWE-252), что приводит к проверке неинициализированной переменной (CWE-457). , возвращая успех, чтобы разрешить обход авторизации для выполнения привилегированного (CWE-863).

Цепь: отказ в обслуживании может быть вызван неинициализированной переменной (CWE-457), которая допускает бесконечный цикл (CWE-835) в результате подключения к неотвечающему серверу.

Читайте также: