Преобразование типа данных с расширением знака вызывает непредвиденное поведение
Этот дефект возникает при преобразовании подписанного или простого char переменная, содержащая возможные отрицательные значения для более широкого целочисленного типа данных (или выполнить арифметическую операцию, которая выполняет преобразование), а затем использовать результирующее значение одним из следующих способов:
Для сравнения с EOF (использование == или !=)
Как индекс массива
В качестве аргумента функции обработки символов в ctype.h, например, isalpha() или isdigit()
При преобразовании подписи char переменная с отрицательным значением для более широкого типа, например int, бит знака сохраняется (расширение знака). Это может привести к конкретным проблемам даже в ситуациях, когда вы думаете, что учли бит знака.
Например, подписанный char значение -1 может представлять символ EOF (конец файла), который является недопустимым символом. Предположим, что char переменная var получает это значение. Если вы лечите var в качестве char переменная, вы можете написать специальный код, чтобы учесть это недопустимое значение символа. Однако при выполнении такой операции, как var++ (включая целочисленное продвижение), оно приводит к значению 0, которое представляет допустимое значение '\0' случайно. С помощью арифметической операции был выполнен переход от недопустимого к допустимому значению.
Даже для отрицательных значений, отличных от -1, преобразование со знаком char к подписанному int может привести к другим проблемам. Например, подписанный char значение -126 эквивалентно unsigned char значение 130 (соответствующее расширенному символу '\202'). При преобразовании значения из char кому int, бит знака сохраняется. Если затем привести результирующее значение к unsigned int, вы получаете неожиданно большое значение, 4294967170 (предполагая 32-битныйint). Если код ожидает unsigned char значение 130 в финале unsigned int переменная, можно увидеть неожиданные результаты.
Основной причиной этой проблемы является расширение знака во время преобразования в более широкий тип. В большинстве архитектур для хранения значений используется двухкомпонентное представление. В этом представлении старший бит указывает знак значения. При преобразовании в более широкий тип преобразование выполняется копированием этого знакового бита во все ведущие биты более широкого типа, так что знак сохраняется. Например, char значение -3 представлено как 11111101 (в предположении, что 8-битный char). При преобразовании в int, представление:
11111111 11111111 11111111 11111101
int. Однако при преобразовании в unsigned int, значение (4294967293) больше не совпадает со значением unsigned char эквивалент оригинала char значение. Если вы не знаете об этой проблеме, вы можете увидеть неожиданные результаты в своем коде.В следующих случаях функция Bug Finder помечает использование переменных после преобразования из char для более широкого типа данных или арифметической операции, которая неявно преобразует переменную в более широкий тип данных:
При сравнении значения переменной с EOF:
A char значение -1 может представлять недопустимый символ EOF или допустимое расширенное символьное значение '\377' (соответствует unsigned char эквивалент, 255). После char переменная приводится к более широкому типу, такому как int, из-за расширения знака, char значение -1, представляющее одно из EOF или '\377' становится int значение -1, представляющее только EOF. unsigned char значение 255 больше не может быть восстановлено из int переменная. Функция поиска ошибок помечает эту ситуацию, чтобы можно было привести переменную к unsigned char сначала (или избегайте charКому-int преобразование или преобразование операции перед сравнением с EOF). Только тогда сравнение с EOF имеет смысл. См. раздел Расширенное знаковое значение по сравнению с EOF.
Если значение переменной используется в качестве индекса массива:
После char переменная приводится к более широкому типу, такому как intиз-за расширения знака все отрицательные значения сохраняют свой знак. Если отрицательные значения используются непосредственно для доступа к массиву, это приводит к переполнению/неполному заполнению буфера. Даже при учете отрицательных значений способ их учета может привести к неправильному считыванию элементов из массива. См. раздел Расширенное знаковое значение, используемое в качестве индекса массива.
При передаче значения переменной в качестве аргумента функции обработки символов:
В соответствии со стандартом C11 (раздел 7.4), если указан целый аргумент, который не может быть представлен как unsigned char или EOF, результирующее поведение не определено. Функция поиска ошибок помечает эту ситуацию, поскольку она отрицательна char значения после преобразования больше не могут быть представлены как unsigned char или EOF. Например, подписанный char значение -126 эквивалентно unsigned char значение 130, но подписанное int значение -126 не может быть представлено как unsigned char или EOF.
Перед преобразованием в более широкий целочисленный тип данных приведите знак или простой char значение явно для unsigned char.
Если вы используете char тип данных, чтобы не представлять символы, а просто как меньший тип данных для сохранения памяти, использование расширения знака char значения могут избежать рисков, упомянутых ранее. Если да, добавьте комментарии к результату или коду, чтобы избежать другой проверки. См. раздел Результаты анализа пространства адресов с помощью исправлений ошибок или обоснований.
| Группа: Программирование |
| Язык: C | C++ |
| По умолчанию: Вкл для рукописного кода, выкл для сгенерированного кода |
Синтаксис командной строки: CHARACTER_MISUSE |
| Воздействие: среднее |
| CWE ID: 704 |
Character value absorbed into EOF | Errno not checked | Find defects (-checkers) | Invalid use of standard library integer routine | Returned value of a sensitive function not checked