Преобразование типа данных с расширением знака вызывает неожиданное поведение
Этот дефект возникает при преобразовании подписанного или простого 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
. The unsigned char
значение 255 больше не может быть восстановлено из int
переменная. Bug Finder помечает эту ситуацию, чтобы можно было привести переменную к unsigned char
сначала (или избегайте char
-то- int
операция преобразования или преобразования перед сравнением с EOF
). Только тогда сравнение с EOF
имеет значение. Смотрите Значение Расширенного Символа Знака По сравнению с EOF.
Если вы используете значение переменных в качестве индекса массива:
После char
переменная приведена к более широкому типу, такому как int
из-за расширения знака все отрицательные значения сохраняют свой знак. Если вы используете отрицательные значения непосредственно для доступа к массиву, вы вызываете переполнение/нижнее течение буфера. Даже когда вы учитываете отрицательные значения, способ их учета может привести к тому, что из массива будут считываться неправильные элементы. Смотрите значение знака-расширенного символа, используемое в качестве индекса массива.
Если вы передаете значение переменных в качестве аргумента в функцию обработки символов:
Согласно стандарту C11 (Раздел 7.4), если вы задаете целочисленный аргумент, который не может быть представлен как unsigned char
или EOF
, результирующее поведение не определено. Bug Finder помечает эту ситуацию, потому что отрицательные char
значения после преобразования уже не могут быть представлены как unsigned char
или EOF
. Например, подписанный char
значение -126 эквивалентно unsigned char
значение 130, но со знаком int
значение -126 не может быть представлено как unsigned char
или EOF
.
Перед преобразованием в более широкий целочисленный тип данных приведите char
со знаком или просто значение явно для
unsigned char
.
Если вы используете char
тип данных не для представления символов, а просто как меньший тип данных для сохранения памяти, использование расширенных знаков char
значения могут избежать вышеупомянутых рисков. Если это так, добавьте комментарии к своему результату или коду, чтобы избежать другого обзора. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
Группа: Программирование |
Язык: C | C++ |
По умолчанию: On для рукописного кода, off для сгенерированного кода |
Синтаксис командной строки: CHARACTER_MISUSE |
Влияние: Средний |
ИДЕНТИФИКАТОР CWE: 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