CertC-DCL23

Guarantee that mutually visible identifiers are unique

Required inputs: IR

According to subclause 6.2.7 of the C Standard [ ISO/IEC 9899:2011],

All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.

(See also undefined behavior 15 of Annex J.)

Further, according to subclause 6.4.2.1,

Any identifiers that differ in a significant character are different identifiers. If two identifiers differ only in nonsignificant characters, the behavior is undefined.

(See also undefined behavior 31 of Annex J.)

Identifiers in mutually visible scopes must be deemed unique by the compiler to prevent confusion about which variable or function is being referenced. Implementations can allow additional nonunique characters to be appended to the end of identifiers, making the identifiers appear unique while actually being indistinguishable.

It is reasonable for scopes that are not visible to each other to have duplicate identifiers. For example, two functions can each have a local variable with the same name because their scopes cannot access each other. But a function's local variable names should be distinct from each other as well as from all static variables declared within the function's file (and from all included header files.)

To guarantee that identifiers are unique, the number of significant characters recognized by the most restrictive compiler used must be determined. This assumption must be documented in the code.

The standard defines the following minimum requirements:

  • 63 significant initial characters in an internal identifier or a macro name. (Each universal character name or extended source character is considered a single character.)
  • 31 significant initial characters in an external identifier. (Each universal character name specifying a short identifier of 0000FFFF or less is considered 6 characters; each universal character name specifying a short identifier of 00010000 or more is considered 10 characters; and each extended source character, if any exist, is considered the same number of characters as the corresponding universal character name.)

Restriction of the significance of an external name to fewer than 255 characters in the standard (considering each universal character name or extended source character as a single character) is an obsolescent feature that is a concession to existing implementations. As a result, it is not necessary to comply with this restriction as long as the identifiers are unique and the assumptions concerning the number of significant characters are documented.

Noncompliant Code Example (Source Character Set)

On implementations that support only the minimum requirements for significant characters required by the standard, this code example is noncompliant because the first 31 characters of the external identifiers are identical:

extern int *global_symbol_definition_lookup_table_a;
extern int *global_symbol_definition_lookup_table_b;
Compliant Solution (Source Character Set)

In a compliant solution, the significant characters in each identifier must differ:

extern int *a_global_symbol_definition_lookup_table;
extern int *b_global_symbol_definition_lookup_table;
Noncompliant Code Example (Universal Character Names)

In this noncompliant code example, both external identifiers consist of four universal character names. Because the first three universal character names of each identifier are identical, both identify the same integer array on implementations that support only the minimum requirements for significant characters required by the standard:

extern int *\U00010401\U00010401\U00010401\U00010401;
extern int *\U00010401\U00010401\U00010401\U00010402;
Compliant Solution (Universal Character Names)

For portability, the first three universal character name combinations used in an identifier must be unique:

extern int *\U00010401\U00010401\U00010401\U00010401;
extern int *\U00010402\U00010401\U00010401\U00010401;
Risk Assessment

Nonunique identifiers can lead to abnormal program termination, denial-of-service attacks, or unintended information disclosure.

Rule Severity Likelihood Remediation Cost Priority Level
DCL23-C Medium Unlikely Low P6 L2
Related Guidelines
ISO/IEC TR 24772:2013 Choice of Clear Names [NAI]
Identifier Name Reuse [YOW]
MISRA C:2012 Rule 5.1 (required)
Rule 5.2 (required)
Rule 5.3 (required)
Rule 5.4 (required)
Rule 5.5 (required)
Bibliography
[ ISO/IEC 9899:2011] Subclause 6.2.7, "Compatible Type and Composite Type"
Subclause 6.4.1, "Keywords"
Excerpt from SEI CERT C Coding Standard: Rules for Developing Safe, Reliable, and Secure Systems (2016 Edition) and SEI CERT C Coding Standard [https://cmu-sei.github.io/secure-coding-standards/sei-cert-c-coding-standard/recommendations/declarations-and-initialization-dcl/dcl23-c], Copyright (C) 1995-2026 Carnegie Mellon University. See section 9.4. "3rd-Party Licenses" in the documentation for full details.

Possible Messages

Key

Text

Severity

Disabled

duplicate_macro_parameter

Macro identifiers shall be distinct.

None

False

external_identifiers_not_distinct

External identifiers not distinct.

None

False

external_identifiers_sharing

External identifiers sharing first {} characters.

None

False

identifier_clashes_with_macro

Identifiers shall be distinct from macro names.

None

False

internal_identifiers_not_distinct

Internal identifiers not distinct.

None

False

internal_identifiers_sharing

Internal identifiers sharing first {} characters.

None

False

macro_identifiers_not_distinct

Macro identifiers shall be distinct.

None

False

macro_name_conflict_with_parameter

Macro name and name of parameter of other currently-defined macro shall be distinct.

None

False

name_reused_in_same_c_name_space

Identifiers sharing first {} characters.

None

False

Options

global_check

global_check : bool = False

If true, the names are compared system-wide, otherwise the MisraC2012 version is used.
 

ignore_command_line_macros

ignore_command_line_macros : bool = False

If global_check is false: whether conflicts with command-line macros should be reported.
 

maxlen

maxlen : int | None = None

Number of significant characters in all identifiers. If set, the option overrides max_external_identifiers and max_internal_identifiers.
 

maxlen_external_identifiers

maxlen_external_identifiers : int | None = None

Number of significant characters in external identifiers. If None, the corresponding translation limit of the active compiler is used.
 

maxlen_internal_identifiers

maxlen_internal_identifiers : int | None = None

Number of significant characters in internal identifiers. If None, the corresponding translation limit of the active compiler is used. Used for the following subrules:
  • colliding identifiers in same scope and name space,
  • reused macro names,
  • duplicated macro parameters names,
  • identifiers colliding with macro names.
 

report_external_identifiers

report_external_identifiers : bool = True

Whether external identifiers should be compared to each other.
 

report_internal_identifiers

report_internal_identifiers : bool = False

Whether internal identifiers should be compared to each other (including macros).
 

report_short_identifiers

report_short_identifiers : bool = True

If true, identifiers shorter than maxlen are considered as well.