Main Content

CWE Rule 665

Improper Initialization

Since R2024a

Description

Rule Description

The product does not initialize or incorrectly initializes a resource, which might leave the resource in an unexpected state when it is accessed or used.

Polyspace Implementation

The rule checker checks for these issues:

  • Call to memset family with unintended value

  • Improper array initialization

  • Overlapping assignment

  • Use of memset with size argument zero

Examples

expand all

Issue

This issue occurs when Polyspace® Bug Finder™ detects a use of the memset or wmemset function with possibly incorrect arguments.

void *memset (void *ptr, int value, size_t num) fills the first num bytes of the memory block that ptr points to with the specified value. If the argument value is incorrect, the memory block is initialized with an unintended value.

The unintended initialization can occur in the following cases.

IssueRiskPossible Fix
The second argument is '0' instead of 0 or '\0'.The ASCII value of character '0' is 48 (decimal), 0x30 (hexadecimal), 069 (octal) but not 0 (or '\0').If you want to initialize with '0', use one of the ASCII values. Otherwise, use 0 or '\0'.
The second and third arguments are probably reversed. For instance, the third argument is a literal and the second argument is not a literal.If the order is reversed, a memory block of unintended size is initialized with incorrect arguments.Reverse the order of the arguments.
The second argument cannot be represented in a byte.If the second argument cannot be represented in a byte, and you expect each byte of a memory block to be filled with that argument, the initialization does not occur as intended.

Apply a bit mask to the argument to produce a wrapped or truncated result that can be represented in a byte. When you apply a bit mask, make sure that it produces an expected result.

For instance, replace memset(a, -13, sizeof(a)) with memset(a, (-13) & 0xFF, sizeof(a)).

Fix

The fix depends on the root cause of the defect. See fixes in the table above and code examples with fixes below.

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Example — Value Cannot Be Represented in a Byte
#include <string.h>

#define SIZE 32
void func(void) {
    char buf[SIZE];
    int c = -2;
    memset(buf, (char)c, sizeof(buf)); //Noncompliant
}

In this example, (char)c cannot be represented in a byte.

Correction — Apply Cast

One possible correction is to apply a cast so that the result can be represented in a byte. Check that the result of the cast is an acceptable initialization value. In this correction, Polyspace does not raise this defect. The cast from signed int to unsigned char is contrary to best practices and Polyspace raises the defect Sign change integer conversion overflow.

#include <string.h>

#define SIZE 32
void func(void) {
    char buf[SIZE   ];
    int c = -2;
    memset(buf, (unsigned char)c, sizeof(buf));// Might Overflow 
}
Correction — Avoid Using memset

One possible correction is to reserve the use of memset only for setting or clearing all bits in a buffer. For instance, in this code, memset is called to clear the bits of the character array buf.

#include <string.h>

#define SIZE 32
void func(void) {
    char buf[SIZE   ];
    int c = -2;
    memset(buf, 0, sizeof(buf));//Compliant 
	/* After clearing buf, use it in operations*/
}
Issue

This issue occurs when Polyspace Bug Finder considers that an array initialization using initializers is incorrect.

This defect applies to normal and designated initializers. In C99, with designated initializers, you can place the elements of an array initializer in any order and implicitly initialize some array elements. The designated initializers use the array index to establish correspondence between an array element and an array initializer element. For instance, the statement int arr[6] = { [4] = 29, [2] = 15 } is equivalent to int arr[6] = { 0, 0, 15, 0, 29, 0 }.

You can use initializers incorrectly in one of the following ways.

IssueRiskPossible Fix

In your initializer for a one-dimensional array, you have more elements than the array size.

Unused array initializer elements indicate a possible coding error.

Increase the array size or remove excess elements.

You place the braces enclosing initializer values incorrectly.

Because of the incorrect placement of braces, some array initializer elements are not used.

Unused array initializer elements indicate a possible coding error.

Place braces correctly.

In your designated initializer, you do not initialize the first element of the array explicitly.

The implicit initialization of the first array element indicates a possible coding error. You possibly overlooked the fact that array indexing starts from 0.

Initialize all elements explicitly.

In your designated initializer, you initialize an element twice.

The first initialization is overridden.

The redundant first initialization indicates a possible coding error.

Remove the redundant initialization.

You use designated and nondesignated initializers in the same initialization.

You or another reviewer of your code cannot determine the size of the array by inspection.

Use either designated or nondesignated initializers.

Fix

The fix depends on the root cause of the defect. See fixes in the table above and code examples with fixes below.

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Example — Incorrectly Placed Braces (C Only)

int arr[2][3]
= {{1, 2},
    {3, 4},
    {5, 6} //Noncompliant
};

In this example, the array arr is initialized as {1,2,0,3,4,0}. Because the initializer contains {5,6}, you might expect the array to be initialized {1,2,3,4,5,6}.

Correction — Place Braces Correctly

One possible correction is to place the braces correctly so that all elements are explicitly initialized.

int a1[2][3]
= {{1, 2, 3},
    {4, 5, 6}
};
Example — First Element Not Explicitly Initialized
int arr[5]
= {
    [1] = 2,      
    [2] = 3,
    [3] = 4,
    [4] = 5
};               //Noncompliant

In this example, arr[0] is not explicitly initialized. It is possible that the programmer did not consider that the array indexing starts from 0.

Correction — Explicitly Initialize All Elements

One possible correction is to initialize all elements explicitly.

int arr[5]
= {
    [0] = 1,
    [1] = 2,      
    [2] = 3,
    [3] = 4,
    [4] = 5
};              
Example — Element Initialized Twice
int arr[5]
= {
    [0] = 1,
    [1] = 2,      
    [2] = 3,
    [2] = 4, //Noncompliant
    [4] = 5
};              

In this example, arr[2] is initialized twice. The first initialization is overridden. In this case, because arr[3] was not explicitly initialized, it is possible that the programmer intended to initialize arr[3] when arr[2] was initialized a second time.

Correction — Fix Redundant Initialization

One possible correction is to eliminate the redundant initialization.

int arr[5]
= {
    [0] = 1,
    [1] = 2,
    [2] = 3,
    [3] = 4,
    [4] = 5
};
Example — Mix of Designated and Nondesignated Initializers
int arr[]
= {
    [0] = 1,
    [3] = 3,
    4,
    [5] = 5,
    6
    };               //Noncompliant

In this example, because a mix of designated and nondesignated initializers are used, it is difficult to determine the size of arr by inspection.

Correction — Use Only Designated Initializers

One possible correction is to use only designated initializers for array initialization.

int arr[]
= {
    [0] = 1,
    [3] = 3,
    [4] = 4,
    [5] = 5,
    [6] = 6
};              
Issue

This issue occurs when there is a memory overlap between the left and right sides of an assignment. For instance, a variable is assigned to itself or one member of a union is assigned to another.

Risk

If the left and right sides of an assignment have memory overlap, the behavior is either redundant or undefined. For instance:

  • Self-assignment such as x=(int)(long)x; is redundant unless x is volatile-qualified.

  • Assignment of one union member to another causes undefined behavior.

    For instance, in the following code:

    • The result of the assignment u1.a = u1.b is undefined because u1.b is not initialized.

    • The result of the assignment u2.b = u2.a depends on the alignment and endianness of the implementation. It is not defined by C standards.

    union {
       char a;
       int b;
    }u1={'a'}, u2={'a'}; //'u1.a' and 'u2.a' are initialized
    
    u1.a = u1.b; 
    u2.b = u2.a;

Fix

Avoid assignment between two variables that have overlapping memory.

Example — Assignment of Union Members
#include <string.h>

union Data {
    int i;
    float f;
};

int main( ) {
    union Data data;
    data.i = 0;
    data.f = data.i; //Noncompliant

    return 0;
}

In this example, the variables data.i and data.f are part of the same union and are stored in the same location. Therefore, part of their memory storage overlaps.

Issue

This issue occurs when you call a function in the memset family with size argument zero. Functions include memset, wmemset, bzero, SecureZeroMemory, RtlSecureZeroMemory, and so on.

Risk

void *memset (void *ptr, int value, size_t num) fills the first num bytes of the memory block that ptr points to with the specified value. A zero value of num renders the call to memset redundant. The memory that ptr points to:

  • Remains uninitialized, if not previously initialized.

  • Is not cleared and can contain sensitive data, if previously initialized.

Fix

Determine if the zero size argument occurs because of a previous error in your code. Fix the error.

Example — Zero Size Argument of memset
#include <stdio.h>
#include <string.h>

void func (unsigned int size)
{
    char str[] = "Buffer to be filled.";
    memset (str,'-',size); //Noncompliant
    puts (str);
}

void calling_func(void) {
    unsigned int buf_size=0;
    func(buf_size);
}

In this example, the argument size of memset is zero.

Check Information

Category: Others

Version History

Introduced in R2024a