CWE Rule 704
Description
Rule Description
The software does not correctly convert an object, resource, or structure from one type to a different type.
Polyspace Implementation
The rule checker checks for these issues:
Cast to pointer pointing to object of different type
Character value absorbed into EOF
Conversion between pointer and integer
Integer conversion overflow
Misuse of sign-extended character value
Precision loss in integer to float conversion
Qualifier removed in conversion
Reading memory reallocated from object of another type without reinitializing first
Sign change integer conversion overflow
Tainted sign change conversion
Unreliable cast of pointer
Unsafe conversion between pointer and integer
Unsigned integer conversion overflow
Wrong allocated object size for cast
Examples
Cast to pointer pointing to object of different type
The issue occurs when you perform a cast between a pointer to an object type and a pointer to a different object type.
If a pointer to an object is cast into a pointer to a different object, the resulting pointer can be incorrectly aligned. The incorrect alignment causes undefined behavior.
Even if the conversion produces a pointer that is correctly aligned, the behavior can be undefined if the pointer is used to access an object.
Exception: You can convert a pointer to object type into a pointer to one of these types:
char
signed char
unsigned char
signed char *p1; unsigned int *p2; void foo(void){ p2 = ( unsigned int * ) p1; /* Non-compliant */ }
In this example, p1
can point to a signed
char
object. However, p1
is cast to a pointer
that points to an object of wider type, unsigned int
.
extern unsigned int read_value ( void ); extern void display ( unsigned int n ); void foo ( void ){ unsigned int u = read_value ( ); unsigned short *hi_p = ( unsigned short * ) &u; /* Non-compliant */ *hi_p = 0; display ( u ); }
In this example, u
is an unsigned int
variable. &u
is cast to a pointer that points to an
object of narrower type, unsigned short
.
On a big-endian machine, the statement *hi_p = 0
attempts
to clear the high bits of the memory location that &u
points to. But, from the result of display(u)
, you might find
that the high bits have not been cleared.
const short *p; const volatile short *q; void foo (void){ q = ( const volatile short * ) p; /* Compliant */ }
In this example, both p
and q
can point
to short
objects. The cast between them adds a
volatile
qualifier only and is therefore
compliant.
Character value absorbed into EOF
This issue occurs
when you perform a data type conversion that makes a valid character
value indistinguishable from EOF
(End-of-File).
Bug Finder flags the defect in one of the following situations:
End-of-File: You perform a data type conversion such as from
int
tochar
that converts a non-EOF character value intoEOF
.You then compare the result with EOF.char ch = (char)getchar()
The conversion can be explicit or implicit.if((int)ch == EOF)
Wide End-of-File: You perform a data type conversion that can convert a non-WEOF wide character value into WEOF, and then compare the result with WEOF.
The data type char
cannot hold the value EOF
that
indicates the end of a file. Functions such as getchar
have
return type int
to accommodate EOF
.
If you convert from int
to char
,
the values UCHAR_MAX
(a valid character value)
and EOF
get converted to the same value -1 and
become indistinguishable from each other. When you compare the result
of this conversion with EOF
, the comparison can
lead to false detection of EOF
. This rationale
also applies to wide character values and WEOF
.
Perform the comparison with EOF
or WEOF
before
conversion.
#include <stdio.h> #include <stdlib.h> #define fatal_error() abort() char func(void) { char ch; ch = getchar(); if (EOF == (int)ch) { //Noncompliant fatal_error(); } return ch; }
In this example, the return value of getchar
is
implicitly converted to char
. If getchar
returns UCHAR_MAX
,
it is converted to -1, which is indistinguishable from EOF. When you
compare with EOF later, it can lead to a false positive.
One possible correction is to first perform the comparison with
EOF, and then convert from int
to char
.
#include <stdio.h> #include <stdlib.h> #define fatal_error() abort() char func(void) { int i; i = getchar(); if (EOF == i) { fatal_error(); } else { return (char)i; } }
Conversion between pointer and integer
The issue occurs when you convert an integral type into a raw pointer type. Polyspace® reports the conversion as a violation of the rule regardless of the sizes of the integral and raw pointer types. For instance, if an integer originates from a pointer and then later, is cast into a pointer, Polyspace flags the conversion from integer to pointer. In this case, the integer and the pointer have the same size.
The mapping between pointers and integers is not always consistent with the addressing structure of the environment.
Converting from integers to pointers can create:
Misaligned pointers or misaligned objects.
Invalid pointer addresses.
Where possible, avoid integer-to-pointer conversions. If you want to convert a
void
pointer to an integer, so that you do not change the
value, use types:
C99 —
intptr_t
oruintptr_t
C90 —
size_t
orssize_t
unsigned int* badintptrcast(void) { int* ptr; unsigned long long int_same_as_ptr ; unsigned int int_smaller_than_ptr; unsigned int* ptr0 = (unsigned int*)0xdeadbeef; //Noncompliant /*int to ptr of same size*/ ptr = (int*)int_same_as_ptr; //Noncompliant /*int to ptr of different size*/ ptr = (int*)int_smaller_than_ptr; //Noncompliant return (unsigned int*)(ptr0 - (unsigned int*)ptr); //Noncompliant }
In this example, Polyspace flags the conversions that might be unsafe. For instance:
The conversion of
0xdeadbeef
tounsigned int*
causes alignment issues for the pointer. Polyspace flags the conversion.The conversion of the
int_same_as_ptr
andint_smaller_than_ptr
toint*
pointers might result in invalid pointer address. Polyspace flags these conversion.The
return
statement castsptrdiff_t
to a pointer. This pointer might not point to an invalid address. Polyspace flags the conversion.
intptr_t
One possible correction is to use intptr_t
types to store
addresses. When storing the result of subtracting two pointers, use the type
ptrdiff_t
.
#include<stdint.h> #include<stddef.h> ptrdiff_t badintptrcast(void) { intptr_t ptr; unsigned long long int_same_as_ptr ; unsigned int int_smaller_than_ptr; intptr_t ptr0 = (intptr_t)0xdeadbeef; //Compliant /*int to ptr of same size*/ ptr = (intptr_t)int_same_as_ptr; //Compliant /*int to ptr of different size*/ ptr = (intptr_t)int_smaller_than_ptr; //Compliant return (ptrdiff_t)ptr0;//Compliant }
Integer conversion overflow
This issue occurs when converting an integer to a
smaller integer type. If the variable does not have enough bytes to represent
the original value, the conversion overflows. For instance, if you perform a
comparison between implementation-defined type time_t
and a
signed integer, Polyspace reports a violation because time_t
might be
implemented as an unsigned integer.
The checker also detects comparison
The exact storage allocation for different floating point types depends on your
processor. See Target processor type (-target)
.
Integer conversion overflows result in undefined behavior.
The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).
You can fix the defect by:
Using a bigger data type for the result of the conversion so that all values can be accommodated.
Checking for values that lead to the overflow and performing appropriate error handling.
In general, avoid conversions to smaller integer types.
See examples of fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
A default Bug Finder analysis might not raise this defect when the input values are unknown and only a subset of inputs cause an issue. To check for defects caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.
char convert(void) { int num = 1000000; return (char)num; //Noncompliant }
In the return statement, the integer variable num
is
converted to a char
. However, an 8-bit or 16-bit
character cannot represent 1000000 because it requires at least 20
bits. So the conversion operation overflows.
One possible correction is to convert to a different integer type that can represent the entire number.
long convert(void) { int num = 1000000; return (long)num; }
Misuse of sign-extended character value
This issue occurs when you
convert a signed or plain char
variable containing possible negative
values to a wider integer data type (or perform an arithmetic operation that does the
conversion) and then use the resulting value in one of these ways:
For comparison with
EOF
(using==
or!=
)As array index
As argument to a character-handling function in
ctype.h
, for instance,isalpha()
orisdigit()
If you convert a signed char
variable with a negative value to a
wider type such as int
, the sign bit is preserved (sign extension).
This can lead to specific problems even in situations where you think you have accounted
for the sign bit.
For instance, the signed char
value of -1 can represent the
character EOF
(end-of-file), which is an invalid character. Suppose a
char
variable var
acquires this value. If you
treat var
as a char
variable, you might want to
write special code to account for this invalid character value. However, if you perform
an operation such as var++
(involving integer promotion), it leads to
the value 0, which represents a valid value '\0'
by accident. You
transitioned from an invalid to a valid value through the arithmetic operation.
Even for negative values other than -1, a conversion from signed
char
to signed int
can lead to other issues.
For instance, the signed char
value -126 is equivalent to the
unsigned char
value 130 (corresponding to an extended character
'\202'
). If you convert the value from char
to
int
, the sign bit is preserved. If you then cast the resulting
value to unsigned int
, you get an unexpectedly large value,
4294967170 (assuming 32-bit int
). If your code expects the
unsigned char
value of 130 in the final unsigned
int
variable, you can see unexpected results.
The underlying cause of this issue is the sign extension during conversion to a wider type. Most architectures use two's complement representation for storing values. In this representation, the most significant bit indicates the sign of the value. When converted to a wider type, the conversion is done by copying this sign bit to all the leading bits of the wider type, so that the sign is preserved. For instance, the char
value of -3 is represented as 11111101
(assuming 8-bit char
). When converted to int
, the representation is:
11111111 11111111 11111111 11111101
int
. However, when converted to unsigned int
, the value (4294967293) is no longer the same as the unsigned char
equivalent of the original char
value. If you are not aware of this issue, you can see unexpected results in your code.In the following cases, Bug Finder flags use of variables after a conversion from
char
to a wider data type or an arithmetic operation that
implicitly converts the variable to a wider data type:
If you compare the variable value with EOF:
A
char
value of -1 can represent the invalid characterEOF
or the valid extended character value'\377'
(corresponding to theunsigned char
equivalent, 255). After achar
variable is cast to a wider type such asint
, because of sign extension, thechar
value -1, representing one ofEOF
or'\377'
becomes theint
value -1, representing onlyEOF
. Theunsigned char
value 255 can no longer be recovered from theint
variable. Bug Finder flags this situation so that you can cast the variable tounsigned char
first (or avoid thechar
-to-int
conversion or converting operation before comparison withEOF
). Only then, a comparison withEOF
is meaningful. See Sign-Extended Character Value Compared with EOF.If you use the variable value as an array index:
After a
char
variable is cast to a wider type such asint
, because of sign extension, all negative values retain their sign. If you use the negative values directly to access an array, you cause buffer overflow/underflow. Even when you account for the negative values, the way you account for them might result in incorrect elements being read from the array. See Sign-Extended Character Value Used as Array Index.If you pass the variable value as argument to a character-handling function:
According to the C11 standard (Section 7.4), if you supply an integer argument that cannot be represented as
unsigned char
orEOF
, the resulting behavior is undefined. Bug Finder flags this situation because negativechar
values after conversion can no longer be represented asunsigned char
orEOF
. For instance, the signedchar
value -126 is equivalent to theunsigned char
value 130, but the signedint
value -126 cannot be represented asunsigned char
orEOF
.
Before conversion to a wider integer data type, cast the signed or plain
char
value explicitly to unsigned
char
.
If you use the char
data type to not represent characters but
simply as a smaller data type to save memory, your use of sign-extended
char
values might avoid the risks mentioned earlier. If so,
add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
#include <stdio.h> #include <stdlib.h> #define fatal_error() abort() extern char parsed_token_buffer[20]; static int parser(char *buf) { int c = EOF; if (buf && *buf) { c = *buf++; } return c; } void func() { if (parser(parsed_token_buffer) == EOF) { //Noncompliant /* Handle error */ fatal_error(); } }
In this example, the function
parser
can traverse a string input buf
. If a
character in the string has the value -1, it can represent either EOF
or
the valid character value '\377'
(corresponding to the unsigned
char
equivalent 255). When converted to the int
variable
c
, its value becomes the integer value -1, which is always
EOF
. The later comparison with EOF
will not detect
if the value returned from parser
is actually
EOF
.
unsigned char
Before ConversionOne possible correction is to cast the plain char
value to
unsigned char
before conversion to the wider
int
type. Only then can you test if the return value of
parser
is really EOF
.
#include <stdio.h> #include <stdlib.h> #define fatal_error() abort() extern char parsed_token_buffer[20]; static int parser(char *buf) { int c = EOF; if (buf && *buf) { c = (unsigned char)*buf++; } return c; } void func() { if (parser(parsed_token_buffer) == EOF) { /* Handle error */ fatal_error(); } }
#include <limits.h> #include <stddef.h> #include <stdio.h> #define NUL '\0' #define SOH 1 /* start of heading */ #define STX 2 /* start of text */ #define ETX 3 /* end of text */ #define EOT 4 /* end of transmission */ #define ENQ 5 /* enquiry */ #define ACK 6 /* acknowledge */ static const int ascii_table[UCHAR_MAX + 1] = { [0]=NUL,[1]=SOH, [2]=STX, [3]=ETX, [4]=EOT, [5]=ENQ,[6]=ACK, /* ... */ [126] = '~', /* ... */ [130/*-126*/]='\202', /* ... */ [255 /*-1*/]='\377' }; int lookup_ascii_table(char c) { int i; i = (c < 0 ? -c : c); return ascii_table[i]; //Noncompliant }
In this example, the char
variable c
is converted to
the int
variable i
. If c
has
negative values, they are converted to positive values before assignment to
i
. However, this conversion can lead to unexpected values when
i
is used as array index. For instance:
If
c
has the value -1 representing the invalid characterEOF
, you want to probably treat this value separately. However, in this example, a value ofc
equal to -1 leads to a value ofi
equal to 1. The functionlookup_ascii_table
returns the valueascii_table[1]
(orSOH
) without the invalid character valueEOF
being accounted for.If you use the
char
data type to not represent characters but simply as a smaller data type to save memory, you need not worry about this issue.If
c
has a negative value, when assigned toi
, its sign is reversed. However, if you access the elements ofascii_table
throughi
, this sign reversal can result in unexpected values being read.For instance, if
c
has the value -126,i
has the value 126. The functionlookup_ascii_table
returns the valueascii_table[126]
(or'~'
) but you probably expected the valueascii_table[130]
(or'\202'
).
Note that the example uses designated initializers for array initialization and does not compile in C++. You can adapt the example appropriately for C++ compilation.
unsigned char
To correct the issues, avoid the conversion from char
to
int
. First, check c
for the value
EOF
. Then, cast the value of the char
variable
c
to unsigned char
and use the result as array
index.
#include <limits.h> #include <stddef.h> #include <stdio.h> #define NUL '\0' #define SOH 1 /* start of heading */ #define STX 2 /* start of text */ #define ETX 3 /* end of text */ #define EOT 4 /* end of transmission */ #define ENQ 5 /* enquiry */ #define ACK 6 /* acknowledge */ static const int ascii_table[UCHAR_MAX + 1] = { [0]=NUL,[1]=SOH, [2]=STX, [3]=ETX, [4]=EOT, [5]=ENQ,[6]=ACK, /* ... */ [126] = '~', /* ... */ [130/*-126*/]='\202', /* ... */ [255 /*-1*/]='\377' }; int lookup_ascii_table(char c) { int r = EOF; if (c != EOF) /* specific handling EOF, invalid character */ r = ascii_table[(unsigned char)c]; /* cast to 'unsigned char' */ return r; }
Precision loss in integer to float conversion
This issue occurs when you cast an integer value to a floating-point type that cannot represent the original integer value.
For instance, the long int
value
1234567890L
is too large for a variable of type
float
.
If the floating-point type cannot represent the integer value, the behavior is undefined (see C11 standard, 6.3.1.4, paragraph 2). For instance, least significant bits of the variable value can be dropped leading to unexpected results.
Convert to a floating-point type that can represent the integer value.
For instance, if the float
data type cannot represent the integer
value, use the double
data type instead.
When writing a function that converts an integer to floating point type, before the conversion, check if the integer value can be represented in the floating-point type. For instance, DBL_MANT_DIG * log2(FLT_RADIX)
represents the number of base-2 digits in the type double
. Before conversion to the type double
, check if this number is greater than or equal to the precision of the integer
that you are converting. To determine the precision of an integer num
, use this code:
size_t precision = 0; while (num != 0) { if (num % 2 == 1) { precision++; } num >>= 1; }
Some implementations provide a builtin function to determine the precision of an
integer. For instance, GCC provides the function
__builtin_popcount
.
#include <stdio.h> int main(void) { long int big = 1234567890L; float approx = big; //Noncompliant printf("%ld\n", (big - (long int)approx)); return 0; }
In this C code, the long int
variable big
is converted to float
.
One possible correction is to convert to the double
data type
instead of float
.
#include <stdio.h> int main(void) { long int big = 1234567890L; double approx = big; printf("%ld\n", (big - (long int)approx)); return 0; }
Qualifier removed in conversion
This checker is deactivated in a default Polyspace as You Code analysis. See Checkers Deactivated in Polyspace as You Code Analysis (Polyspace Access).
This issue occurs during a pointer
conversion when one pointer has a qualifier and the other does not. For example, when
converting from a const int*
to an int*
, the
conversion removes the const
qualifier.
This defect applies only for projects in C.
Qualifiers such as const
or volatile
in a pointer declaration:
const int* ptr;
const
or volatile
. These qualifiers act as instructions to the compiler. For instance, a const
object is not supposed to be modified in the code and a
volatile
object is not supposed to be optimized away by the compiler.If a second pointer points to the same object but does not use the same qualifier,
the qualifier on the first pointer is no longer valid. For instance, if a
const int*
pointer and an int*
pointer
point to the same object, you can modify the object through the second pointer and
violate the contract implied by the const
qualifier in the first
pointer.
If you intend to convert from one pointer to another, declare both pointers with the same qualifiers.
void implicit_cast(void) { const char cc, *pcc = &cc; char * quo; quo = &cc; //Noncompliant quo = pcc; //Noncompliant read(quo); }
During the assignment to the character q
,
the variables, cc
and pcc
, are
converted from const char
to char
.
The const
qualifier is removed during the conversion
causing a defect.
One possible correction is to add the same
qualifiers to the new variables. In this example, changing q
to
a const char
fixes the defect.
void implicit_cast(void) { const char cc, *pcc = &cc; const char * quo; quo = &cc; quo = pcc; read(quo); }
One possible correction is to remove the qualifiers
in the converted variable. In this example, removing the const
qualifier
from the cc
and pcc
initialization
fixes the defect.
void implicit_basic_cast(void) { char cc, *pcc = &cc; char * quo; quo = &cc; quo = pcc; read(quo); }
Reading memory reallocated from object of another type without reinitializing first
This issue occurs when you do the following in sequence:
Reallocate memory to an object with a type that is different from the original allocation.
For instance, in this code snippet, a memory originally allocated to a pointer with type
struct A*
is reallocated to a pointer with typestruct B*
:struct A; struct B; struct A *Aptr = (struct A*) malloc(sizeof(struct A)); struct B *Bptr = (struct B*) realloc(Aptr, sizeof(struct B));
Read from this reallocated memory without reinitializing the memory first.
Read accesses on the pointer to the reallocated memory can happen through pointer dereference or array indexing. Passing the pointer to a function that takes a pointer to a
const
-qualified object as the corresponding parameter also counts as a read access.
Reading from reallocated memory that has not been reinitialized leads to undefined behavior.
Reinitialize memory after reallocation and before the first read access.
The checker considers any write access on the pointer to the reallocated
memory as satisfying the reinitialization requirement (even if the object might
only be partially reinitialized). Write accesses on the pointer to the
reallocated memory can happen through pointer dereference or array indexing.
Passing the pointer to a function that takes a pointer to a
non-const
-qualified object as the corresponding parameter
also counts as a write access.
#include<stdlib.h> struct group { char *groupFirst; int groupSize; }; struct groupWithID { int groupID; char *groupFirst; int groupSize; }; char* readName(); int readSize(); void createGroup(int nextAvailableID) { struct group *aGroup; struct groupWithID *aGroupWithID; aGroup = (struct group*) malloc(sizeof(struct group)); if(!aGroup) { /*Handle error*/ } aGroup->groupFirst = readName(); aGroup->groupSize = readSize(); /* Reassign to group with ID */ aGroupWithID = (struct groupWithID*) realloc(aGroup, sizeof(struct groupWithID)); //Noncompliant if(!aGroupWithID) { free(aGroup); /*Handle error*/ } if(aGroupWithID -> groupSize > 0) { /* Noncompliant */ /* ... */ } /* ...*/ free(aGroupWithID); }
In this example, the memory allocated to a group*
pointer
using the malloc
function is reallocated to a
groupWithID*
pointer using the realloc
function. There is a read access on the reallocated memory before the memory is
reinitialized, causing a violation. The reallocation operation allocates memory
the size of which is not a multiple of the destination type, causing a violation
because of the issue Wrong allocated object size for
cast.
Reinitialize the memory assigned to the groupWithID*
pointer before the first read access. All bits of the memory can be
reinitialized using the memset
function.
#include<stdlib.h> #include<string.h> struct group { char *groupFirst; int groupSize; }; struct groupWithID { int groupID; char *groupFirst; int groupSize; }; char* readName(); int readSize(); void createGroup(int nextAvailableID) { struct group *aGroup; struct groupWithID *aGroupWithID; aGroup = (struct group*) malloc(sizeof(struct group)); if(!aGroup) { /*Handle error*/ } aGroup->groupFirst = readName(); aGroup->groupSize = readSize(); /* Reassign to group with ID */ aGroupWithID = (struct groupWithID*) realloc(aGroup, sizeof(struct groupWithID)); //Noncompliant if(!aGroupWithID) { free(aGroup); /*Handle error*/ } memset(aGroupWithID, 0 , sizeof(struct groupWithID)); /* Reinitialize group */ if(aGroupWithID -> groupSize > 0) { /* ... */ } /* ...*/ free(aGroupWithID); }
The violation because of the issue Wrong allocated object size for cast remains in this corrected code.
Sign change integer conversion overflow
This issue occurs when converting an unsigned integer to a signed integer. If the variable does not have enough bytes to represent both the original constant and the sign bit, the conversion overflows.
The exact storage allocation for different floating point types depends on your
processor. See Target processor type (-target)
.
The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).
See examples of fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
A default Bug Finder analysis might not raise this defect when the input values are unknown and only a subset of inputs cause an issue. To check for defects caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.
char sign_change(void) { unsigned char count = 255; return (char)count; //Noncompliant }
In the return statement, the unsigned character
variable count
is converted to a signed character.
However, char
has 8 bits, 1 for the sign of the
constant and 7 to represent the number. The conversion operation overflows
because 255 uses 8 bits.
One possible correction is using a larger integer
type. By using an int
, there are enough bits to
represent the sign and the number value.
int sign_change(void) { unsigned char count = 255; return (int)count; }
Tainted sign change conversion
This issue occurs when values from unsecure sources are converted, implicitly or explicitly, from signed to unsigned values.
For example, functions that use size_t
as arguments implicitly convert the argument to an unsigned integer. Some functions that implicitly convert size_t
are:
bcmp memcpy memmove strncmp strncpy calloc malloc memalign
If you convert a small negative number to unsigned, the result is a large positive number. The large positive number can create security vulnerabilities. For example, if you use the unsigned value in:
Memory size routines — causes allocating memory issues.
String manipulation routines — causes buffer overflow.
Loop boundaries — causes infinite loops.
To avoid converting unsigned negative values, check that the value being converted is within an acceptable range. For example, if the value represents a size, validate that the value is not negative and less than the maximum value size.
By default, Polyspace assumes that data from external sources are tainted. See Sources of Tainting in a Polyspace Analysis. To consider
any data that does not originate in the current scope of Polyspace analysis as
tainted, use the command line option -consider-analysis-perimeter-as-trust-boundary
.
#include <stdlib.h> #include <string.h> #include <stdio.h> enum { SIZE10 = 10, SIZE100 = 100, SIZE128 = 128 }; void bug_taintedsignchange(void) { int size; scanf("%d",&size); char str[SIZE128] = ""; if (size<SIZE128) { memset(str, 'c', size); //Noncompliant } }
In this example, a char
buffer is created
and filled using memset
. The size argument to memset
is
an input argument to the function.
The call to memset
implicitly converts size
to
unsigned integer. If size
is a large negative number,
the absolute value could be too large to represent as an integer,
causing a buffer overflow.
size
One possible correction is to check if size
is
inside the valid range. This correction checks if size
is
greater than zero and less than the buffer size before calling memset
.
#include <stdlib.h> #include <string.h> #include <stdio.h> enum { SIZE10 = 10, SIZE100 = 100, SIZE128 = 128 }; void corrected_taintedsignchange(void) { int size; scanf("%d",&size); char str[SIZE128] = ""; if (size>0 && size<SIZE128) { memset(str, 'c', size); } }
Unreliable cast of pointer
This issue occurs
when a pointer is implicitly cast to a data type different from its
declaration type. Such an implicit casting can take place, for instance,
when a pointer to data type char
is assigned the
address of an integer.
This defect applies only if the code language for the project is C.
Casting a pointer to data type different from its declaration type can result in issues such as buffer overflow. If the cast is implicit, it can indicate a coding error.
Avoid implicit cast of a pointer to a data type different from its declaration type.
See examples of fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
#include <string.h> void Copy_Integer_To_String() { int src[]={1,2,3,4,5,6,7,8,9,10}; char buffer[]="Buffer_Text"; strcpy(buffer,src); //Noncompliant /* Defect: Implicit cast of (int*) to (char*) */ }
src
is declared as an int*
pointer.
The strcpy
statement, while copying to buffer
,
implicitly casts src
to char*
.
One possible correction is to declare the pointer src
with
the same data type as buffer
.
#include <string.h> void Copy_Integer_To_String() { /* Fix: Declare src with same type as buffer */ char *src[10]={"1","2","3","4","5","6","7","8","9","10"}; char *buffer[10]; for(int i=0;i<10;i++) buffer[i]="Buffer_Text"; for(int i=0;i<10;i++) buffer[i]= src[i]; }
Unsafe conversion between pointer and integer
This issue occurs when you convert between a pointer type, such as
intptr_t
, or
uintprt_t
, and an integer type,
such as enum
,
ptrdiff_t
, or
pid_t
, or vice versa.
The mapping between pointers and integers is not always consistent with the addressing structure of the environment.
Converting from pointers to integers can create:
Truncated or out of range integer values.
Invalid integer types.
Converting from integers to pointers can create:
Misaligned pointers or misaligned objects.
Invalid pointer addresses.
Where possible, avoid pointer-to-integer or integer-to-pointer
conversions. If you want to convert a void
pointer
to an integer, so that you do not change the value, use types:
C99 —
intptr_t
oruintptr_t
C90 —
size_t
orssize_t
unsigned int *badintptrcast(void) { unsigned int *ptr0 = (unsigned int *)0xdeadbeef; //Noncompliant char *ptr1 = (char *)0xdeadbeef; unsigned int *explicit_ptr = reinterpret_cast<unsigned int*>(0xdeadbeef); //Noncompliant return (unsigned int *)(ptr0 - (unsigned int *)ptr1); //Noncompliant }
In this example, there are four conversions, three unsafe conversions and one safe conversion.
The conversion of
0xdeadbeef
to anunsigned int*
causes alignment issues for the pointer. Polyspace flags this conversion.The conversion of
0xdeadbeef
to achar *
is not flagged because there are no alignment issues forchar
.The explicit
reinterpret_cast
of0xdeadbeef
to anunsigned int*
causes alignment issues for the pointer. Polyspace flags this conversion.The conversion in the return casts
ptrdiff_t
to a pointer. This pointer might point to an invalid address. Polyspace flags this conversion.
intptr_t
One possible correction is to use intptr_t
types to store the pointer address 0xdeadbeef
.
#include <stdint.h> unsigned int *badintptrcast(void) { intptr_t iptr0 = (intptr_t)0xdeadbeef; return (unsigned int *)iptr0; }
Unsigned integer conversion overflow
This issue occurs when converting an unsigned integer to a smaller unsigned integer type. If the variable does not have enough bytes to represent the original constant, the conversion overflows.
The exact storage allocation for different floating point types depends on your
processor. See Target processor type (-target)
.
Integer conversion overflows result in undefined behavior.
The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).
You can fix the defect by:
Using a bigger data type for the result of the conversion so that all values can be accommodated.
Checking for values that lead to the overflow and performing appropriate error handling.
In general, avoid conversions to smaller integer types.
See examples of fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
A default Bug Finder analysis might not raise this defect when the input values are unknown and only a subset of inputs cause an issue. To check for defects caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.
unsigned char convert(void) { unsigned int unum = 1000000U; return (unsigned char)unum; //Noncompliant }
In the return statement, the unsigned integer
variable unum
is converted to an unsigned character
type. However, the conversion overflows because 1000000 requires at
least 20 bits. The C programming language standard does not view unsigned
overflow as an error because the program automatically reduces the
result by modulo the maximum value plus 1. In this example, unum
is
reduced by modulo 2^8
because a character data
type can only represent 2^8-1
.
One possible correction is to convert to a different integer
type that can represent the entire number. For example, long
.
unsigned long convert(void) { unsigned int unum = 1000000U; return (unsigned long)unum; }
Wrong allocated object size for cast
This issue occurs during pointer conversion when the pointer’s address is misaligned. If a pointer is converted to a different pointer type, the size of the allocated memory must be a multiple of the size of the destination pointer.
Dereferencing a misaligned pointer has undefined behavior and can cause your program to crash.
Suppose you convert a pointer ptr1
to ptr2
.
If ptr1
points to a buffer of N
bytes and
ptr2
is a
pointer where
type
*sizeof(
is
type
)n
bytes, make sure that N
is an integer
multiple of n
.
See examples of fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
#include <stdlib.h> void dyn_non_align(void){ void *ptr = malloc(13); long *dest; dest = (long*)ptr; //Noncompliant }
In this example, the software raises a defect on the
conversion of ptr
to a long*
. The dynamically
allocated memory of ptr
, 13 bytes, is not a multiple of the size of
dest
, 4 bytes. This misalignment causes the Wrong allocated object size for cast defect.
One possible correction is to use a pointer size that is a multiple of the destination size. In this example, resolve the defect by changing the allocated memory to 12 instead of 13.
#include <stdlib.h> void dyn_non_align(void){ void *ptr = malloc(12); long *dest; dest = (long*)ptr; }
#include <stdlib.h> void *my_alloc(unsigned int size) { void *ptr_func = malloc(size); if(ptr_func == NULL) exit(-1); return ptr_func; } void fun_non_align(void){ int *dest1; char *dest2; dest1 = (int*)my_alloc(13); //Noncompliant dest2 = (char*)my_alloc(13); //Compliant }
In this example, the software raises a defect on the conversion
of the pointer returned by my_alloc(13)
to an int*
in
line 11. my_alloc(13)
returns a pointer with a
dynamically allocated size of 13 bytes. The size of dest1
is
4 bytes, which is not a divisor of 13. This misalignment causes the Wrong allocated object size for cast defect.
In line 12, the same function call, my_alloc(13)
,
does not call a defect for the conversion to dest2
because
the size of char*
, 1 byte, a divisor of 13.
One possible correction is to use a pointer size that is a multiple
of the destination size. In this example, resolve the defect by changing
the argument for my_alloc
to a multiple of 4.
#include <stdlib.h> void *my_alloc(unsigned int size) { void *ptr_func = malloc(size); if(ptr_func == NULL) exit(-1); return ptr_func; } void fun_non_align(void){ int *dest1; char *dest2; dest1 = (int*)my_alloc(12); dest2 = (char*)my_alloc(13); }
Check Information
Category: Others |
Version History
Introduced in R2023aR2024b: No violation reported in lambda expressions containing functions with captured arguments
Polyspace does not report a violation if you call a function inside of a lambda expression where the function contains an argument captured by the lambda expression. For example:
#include <iostream> #include <functional> void greet(const std::string& name) { std::cout << "Hello, " << name << "!" << std::endl; } int main() { std::string name = "Alice"; auto lambda = [name]() { greet(name); //Compliant }; lambda(); return 0; }
R2024b: Violation reported on conversion of qualified object pointers
Polyspace does not report a violation if you convert pointers to nonqualified object type into a pointer to one of the following types:
char
signed char
unsigned char
Polyspace reports a violation if you convert pointers to qualified objects even
if the destination type is one of char*
, signed
char*
, or unsigned char*
.
See Also
External Websites
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)