CertC-PRE13¶
Use the Standard predefined macros to test for versions and features
Required inputs: IR
The C Standard defines a set of predefined macros (see subclause 6.10.8) to help the user determine if the implementation being used is a conforming implementation, and if so, to which version of the C Standard it conforms. These macros can also help the user to determine which of the standard features are implemented.
The following tables list these macros and indicate in which version of the C Standard they were introduced. The following macros are required:
| Macro Name | C90 | C99 | C11 |
|---|---|---|---|
__STDC__ |
✓ | ✓ | ✓ |
__STDC_HOSTED__ |
✓ | ✓ | |
__STDC_VERSION__1 |
✓ | ✓ | |
__DATE__ |
✓ | ✓ | ✓ |
__FILE__ |
✓ | ✓ | ✓ |
__LINE__ |
✓ | ✓ | ✓ |
__TIME__ |
✓ | ✓ | ✓ |
The following are optional environment macros:
| Macro Name | C90 | C99 | C11 |
|---|---|---|---|
__STDC_ISO_10646__ |
✓ | ✓ | |
__STDC_MB_MIGHT_NEQ_WC__ |
✓ | ✓ | |
__STDC_UTF_16__ |
✓ | ||
__STDC_UTF_32__ |
✓ |
The following are optional feature macros:
| Macro Name | C90 | C99 | C11 |
|---|---|---|---|
__STDC_ANALYZABLE__ |
✓ | ||
__STDC_IEC_559__ |
✓ | ✓ | |
__STDC_IEC_559_COMPLEX__ |
✓ | ✓ | |
__STDC_LIB_EXT1__ |
✓ | ||
__STDC_NO_ATOMICS__ |
✓ | ||
__STDC_NO_COMPLEX__ |
✓ | ||
__STDC_NO_THREADS__ |
✓ | ||
__STDC_NO_VLA__ |
✓ |
The following is optional and is defined by the user:
| Macro Name | C90 | C99 | C11 |
|---|---|---|---|
__STDC_WANT_LIB_EXT1__ |
✓ |
Noncompliant Code Example (Checking Value of Predefined Macro)
C Standard predefined macros should never be tested for a value before the macro is tested for definition, as shown in this noncompliant code example:
#include <stdio.h>
int main(void) {
#if (__STDC__ == 1)
printf("Implementation is ISO-conforming.\n");
#else
printf("Implementation is not ISO-conforming.\n");
#endif
/* ... */
return 0;
}
Compliant Solution (Testing for Definition of Macro)
In this compliant solution, the definition of the predefined macro
__STDC__ is
tested before the value of the macro is tested:
#include <stdio.h>
int main(void) {
#if defined(__STDC__)
#if (__STDC__ == 1)
printf("Implementation is ISO-conforming.\n");
#else
printf("Implementation is not ISO-conforming.\n");
#endif
#else /* !defined(__STDC__) */
printf("__STDC__ is not defined.\n");
#endif
/* ... */
return 0;
}
Compliant Solution (Test for Optional Feature)
This compliant solution tests to see if the C11 predefined macro
__STDC_ANALYZABLE__ is
defined and what value the implementation has given the macro:
#include <stdio.h>
int main(void) {
#if defined (__STDC__)
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */
#if defined(__STDC_ANALYZABLE__)
#if (__STDC_ANALYZABLE__ == 1)
printf("Compiler conforms to Annex L (Analyzability).\n");
#else
printf("Compiler does not support Annex L (Analyzability).\n");
#endif
#else
printf("__STDC_ANALYZABLE__ is not defined.\n");
#endif
#else
printf("Compiler not C11.\n");
#endif
#else
printf("Compiler not Standard C.\n");
#endif
return 0;
}
Compliant Solution (Optional Language Features)
This compliant solution checks for the C11 optional language features in Annex K. If Annex K is supported by the implementation, the functions defined in Annex K are used; if Annex K is not supported, then the standard library functions are used. (See DCL09-C. Declare functions that return errno with a return type of errno_t .)
#if defined(__STDC_LIB_EXT1__)
#if (__STDC_LIB_EXT1__ >= 201112L)
#define USE_EXT1 1
#define __STDC_WANT_LIB_EXT1__ 1 /* Want the ext1 functions */
#endif
#endif
#include <string.h>
#include <stdlib.h>
int main(void) {
char source_msg[] = "This is a test.";
char *msg = malloc(sizeof(source_msg) + 1);
if (msg != NULL) {
#if defined(USE_EXT1)
strcpy_s(msg, sizeof msg, source_msg);
#else
strcpy(msg, source_msg);
#endif
}
else {
return EXIT_FAILURE;
}
return 0;
}
Compliant Solution (Optional Language Features)
#if defined(__STDC_LIB_EXT1__)
#if (__STDC_LIB_EXT1__ >= 201112L)
#define USE_EXT1 1
#define __STDC_WANT_LIB_EXT1__ 1 /* Want the ext1 functions */
#endif
#endif
#include <string.h>
#include <stdlib.h>
#if !defined(USE_EXT1)
#include "safe_str_lib.h"
#endif
int main(void) {
char source_msg[] = "This is a test.";
char *msg = malloc(sizeof(source_msg) + 1);
if (msg != NULL) {
strcpy_s(msg, sizeof msg, source_msg);
}
else {
return EXIT_FAILURE;
}
return 0;
}
Risk Assessment
Not testing for language features or the version of the implementation being used can lead to unexpected or undefined program behavior.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| PRE13-C | Low | Probable | Low | P6 | L2 |
Related Guidelines
| ISO/IEC TR 24772:2013 | Pre-processor Directives [NMP] |
| ISO/IEC 9899:2011 |
6.10.8, "Predefined macro names" K.3.7.1, "Copying functions" |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
macro_value_test_without_definition_check |
Check that a macro is defined before testing its value in an #if |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
macros¶
macros
Optional set of macros to restrict the check to.Type: set[bauhaus.analysis.config.MacroName]
Default:
{'__DATE__', '__FILE__', '__LINE__', '__STDC_ANALYZABLE__', '__STDC_HOSTED__', '__STDC_IEC_559_COMPLEX__', '__STDC_IEC_559__', '__STDC_ISO_10646__', '__STDC_LIB_EXT1__', '__STDC_MB_MIGHT_NEQ_WC__', '__STDC_NO_ATOMICS__', '__STDC_NO_COMPLEX__', '__STDC_NO_THREADS__', '__STDC_NO_VLA__', '__STDC_UTF_16__', '__STDC_UTF_32__', '__STDC_VERSION__', '__STDC_WANT_LIB_EXT1__', '__STDC__', '__TIME__'}