Main Content

CERT C: Rec. DCL06-C

Use meaningful symbolic constants to represent literal values

Description

Rule Definition

Use meaningful symbolic constants to represent literal values.1

Polyspace Implementation

The rule checker checks for these issues:

  • Hard-coded buffer size.

  • Hard-coded loop boundary.

Examples

expand all

Issue

Hard-coded buffer size occurs when you use a numerical value instead of a symbolic constant when declaring a memory buffer such as an array.

Risk

Hard-coded buffer size causes the following issues:

  • Hard-coded buffer size increases the likelihood of mistakes and therefore maintenance costs. If a policy change requires developers to change the buffer size, they must change every occurrence of the buffer size in the code.

  • Hard-constant constants can be exposed to attack if the code is disclosed.

Fix

Use a symbolic name instead of a hard-coded constant for buffer size. Symbolic names include const-qualified variables, enum constants, or macros.

enum constants are recommended.

  • Macros are replaced by their constant values after preprocessing. Therefore, they can expose the loop boundary.

  • enum constants are known at compilation time. Therefore, compilers can optimize the loops more efficiently.

    const-qualified variables are usually known at run time.

Example - Hard-Coded Buffer Size
int table[100]; //Noncompliant

void read(int);

void func(void) {
    for (int i=0; i<100; i++) //Noncompliant
        read(table[i]);
}

In this example, the size of the array table and the loop boundary in the for loop are hard-coded.

Correction — Use Symbolic Name

One possible correction is to replace the hard-coded size with a symbolic name.

const int MAX_1 = 100;        
#define MAX_2 100
enum { MAX_3 = 100 };

int table_2[MAX_2];
int table_3[MAX_3];

void read(int);

void func(void) {
    int table_1[MAX_1];
    for (int i=0; i < MAX_1; i++)
        read(table_1[i]);
    for (int i=0; i < MAX_2; i++)
        read(table_2[i]);
    for (int i=0; i < MAX_3; i++)
        read(table_3[i]);
}
Issue

Hard-coded loop boundary occurs when you use a numerical value instead of symbolic constant for the boundary of a for, while or do-while loop.

Risk

Hard-coded loop boundary causes the following issues:

  • Hard-coded loop boundary makes the code vulnerable to denial of service attacks when the loop involves time-consuming computation or resource allocation.

  • Hard-coded loop boundary increases the likelihood of mistakes and maintenance costs. If a policy change requires developers to change the loop boundary, they must change every occurrence of the boundary in the code.

    For instance, the loop boundary is 10000 and represents the maximum number of client connections supported in a network server application. If the server supports more clients, you must change all instances of the loop boundary in your code. Even if the loop boundary occurs once, you have to search for a numerical value of 10000 in your code. The numerical value can occur in places other than the loop boundary. You must browse through those places before you find the loop boundary.

Fix

Use a symbolic name instead of a hard-coded constant for loop boundary. Symbolic names include const-qualified variables, enum constants or macros.enum constants are recommended because:

  • Macros are replaced by their constant values after preprocessing. Therefore, they can expose the buffer size.

  • enum constants are known at compilation time. Therefore, compilers can allocate storage for them more efficiently.

    const-qualified variables are usually known at run time.

Example - Hard-Coded Loop Boundary
void performOperation(int);

void func(void) {
    for (int i=0; i<100; i++) //Noncompliant
        performOperation(i);
}

In this example, the boundary of the for loop is hard-coded.

Correction — Use Symbolic Name

One possible correction is to replace the hard-coded loop boundary with a symbolic name.

const int MAX_1 = 100;
#define MAX_2 100
enum { MAX_3 = 100 };

void performOperation_1(int);
void performOperation_2(int);
void performOperation_3(int);

void func(void) {
    for (int i=0; i<MAX_1; i++)
        performOperation_1(i);
    for (int i=0; i<MAX_2; i++)
        performOperation_2(i);
    for (int i=0; i<MAX_3; i++)
        performOperation_3(i);
}

Check Information

Group: Rec. 02. Declarations and Initialization (DCL)

Version History

Introduced in R2019a


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.