GitHub
CERT Secure Coding

MSC23-C. Beware of vendor-specific library and language differences

When compiling with a specific vendor's implementation of the C language, and related libraries, be aware that, unfortunately, standards conformance can differ from vendor to vendor. Be certain to read your vendor's documentation to reduce the likelihood of accidentally relying on implementation-specific behavior or deviations.

Implementation-Specific Deviations

Implementation-specific deviations are listed below. The Version column lists the latest version of the compiler or library that exhibits the behavior.

Microsoft Visual Studio

APIDescriptionVersion
Variable-length arraysAbsent2012
static and type qualifiers in
parameter array declarators
Absent2012
_Static_assert Absent; can use static_assert , as in C++112012
_Noreturn Absent; can use __declspec(noreturn) 2012
inline Absent; can use __inline 2012
Hexadecimal floating-point constantsAbsent2012
Compound literalsAbsent2012
Designated initializersAbsent2012
Implicit function declarationsSupport was removed in C11, but it is still supported in MSVC (with diagnostic)2012
Mixed declarations and codeAbsent2012
_Pragma
Absent; can use __pragma 2012
_Bool Absent2012
_Complex Absent2012
__func__ Absent; can use __FUNCTION__ 2012

idempotent type qualifiers

Diagnosed, but functional2012
_Thread_local Absent; can use __declspec(thread)
<complex.h>Absent; __STDC_NO_COMPLEX__ is not defined2012
isblank() Absent2012
<fenv.h>Absent2012
<inttypes.h>Absent2012

float_t , double_t , HUGE_VALF, HUGE_VALL, INFINITY, NAN

Absent2012
#pragma FP_CONTRACT Spelled fp_contract instead of FP_CONTRACT 2012
fpclassify() Absent, use _fpclass() instead2012
isfinite() , isinf() Absent, use _finite() or _finitef() instead2012
isnan() Absent, use _isnan() or _isnanf() instead2012
isnormal() Absent, use _fpclass() instead2012
signbit() Absent2012
acosh() , asinh() , atanh() Absent2012
exp2() , expm1() , ilogb() , log1p() ,
log2()
Absent2012
scalbn() Absent; use _scalb() (or _scalbf() on x64 targets only) instead2012
cbrt() Absent2012
erf() , erfc() , lgamma() , tgamma() Absent2012
nearbyint() , rint() , lrint() ,
round() , lround() , trunk()
Absent2012
remainder() , remquo() Absent2012
copysign() Absent; use _copysign() instead2012
nan() , nexttoward() Absent2012
nextafter() Absent; use _nextafter() or _nextafterf() instead2012
fdim() , fmax(), fmin() Absent2012
fma() Absent2012
isgreater() , isgreaterequal() ,
isless() , islessequal() ,
isunordered()
Absent2012
<stdalign.h> Absent
va_copy() Absent2012
<stdatomic.h> Absent; __STDC_NO_ATOMICS__ is not defined2012
<stdbool.h> Absent; _Bool is not supported in /TC mode, but bool is supported in /TP mode2012
max_align_t Absent2012
Printing format specifier type field S is MSVC-specific; c , s , and z are not conforming [ ISO/IEC 9899-2011 ]; F is unsupported2012
Printing format specifier size field I , I32 and I64 are MSVC-specific; h , w and l are not conforming [ ISO/IEC 9899-2011 ]; hh , j , z and t unsupported2012
Scanning format specifier type field S is MSVC-specific; c and s are not conforming [ ISO/IEC 9899-2011 ]; p is unsupported2012
Scanning format specifier size field I64 is MSVC-specific; h , l , and L prefixes are not conforming [ ISO/IEC 9899-2011 ]; hh , j , z , and
t are unsupported
2012
snprintf() Absent; beware that _snprintf() 's semantics are sufficiently different that it is not advisable as a replacement2012
vfscanf() , vscanf() , vsscanf() Absent2012
fopen() , freopen() Mode parameter not conforming [ ISO/IEC 9899-2011 ]; t , c , n , N , S , R , T , D and css are MSVC
extensions; x is unsupported; see remarks
2012
atoll() Absent; use _atoi64() instead2012
strtof() , strtold() Absent2012
strtoll() Absent; use _strtoi64() instead2012
strtoull() Absent; use _strtoui64() instead2012
aligned_alloc() Absent; use _aligned_malloc() instead (beware, the parameter order is reversed)2012
at_quick_exit() , quick_exit() Absent2012
_Exit() Absent; use _exit() instead2012
<stdnoreturn.h>Absent; use __declspec(noreturn) instead2012
<tgmath.h> Absent2012
<threads.h> Absent; __STDC_NO_THREADS__ is not defined2012
TIME_UTC, struct timespec,
timespec_get()
Absent2012
strftime(), wcsftime() z is not conforming [ ISO/IEC 9899-2011 ]; C , D , e , F , g , G , h , n , r , R , t , T , u , V unsupported2012
<uchar.h> Absent2012
vfwscanf() , vswscanf() , vwscanf() Absent2012
fwide() Unsupported2012
wcstof() , wcstold() Absent2012
wcstoll() Absent; use _wcstoi64() instead2012
wcstoull() Absent; use _wcstoui64() instead2012
iswblank() Absent2012
FLT_EVAL_METHOD , *_HAS_SUBNORM ,
*_DECIMAL_DIG , *_TRUE_MIN
Absent2012
__STDC_LIB_EXT1__,
__STDC_WANT_LIB_EXT1__
Not defined; instead, MSVC uses __STDC_SECURE_LIB__ and __STDC_WANT_SECURE_LIB__ 2012
fopen_s(), freopen_s() Uses the same mode strings as fopen() ; u prefix is unsupported; see remarks2012
vfscanf_s() , vscanf_s() ,
vsscanf_s()
Absent2012
constraint_handler_t ,
set_constraint_handler_s(), abort_handler_s(), ignore_handler_s()
Absent; use _invalid_parameter_handler and _set_invalid_parameter_handler() instead.  Beware that the _invalid_parameter_handler signature is considerably different than
that of constraint_handler_t .  No replacement for abort_handler_s() or
ignore_handler_s()
2012
bsearch_s() Not conforming [ ISO/IEC 9899-2011 ]; beware that the comparison function pointer's signature is
different from the standard; namely that the context parameter comes first in MSVC but last in ISO C
2012
qsort_s() Not conforming [ ISO/IEC 9899-2011 ]; beware that the comparison function's pointer signature is different
from the standard; namely that the context parameter comes first in MSVC but last in ISO C
2012
strtok_s() Not conforming [ ISO/IEC 9899-2011 ]; the function signature is missing the rsize_t * parameter2012
memset_s(), strerrorlen_s() Absent2012
gmtime_s() , localtime_s() Not conforming [ ISO/IEC 9899-2011 ]; the function signature has the parameters reversed and returns
errno_t instead of struct tm *
2012
snwprintf_s() Absent; use _snwprintf_s() instead.  Note that the parameters differ from the ISO C signature2012
vfwscanf_s() , vswscanf_s() ,
vwscanf_s()
Absent2012

vsnwprintf_s()

Absent, use _vsnwprintf_s() instead.  Note that the parameters differ from the ISO C signature2012
wcstok_s() Not conforming [ ISO/IEC 9899-2011 ]; the function signature is missing the rsize_t * parameter2012

fopen() & freopen()

The C standard does not specify what happens with Windows newline characters (CRLF), and so care should be taken when working with text files.  For instance:

Non-compliant code
#include <stdio.h>
 
void func( void ) {
  FILE *fp = fopen("text_file.txt", "r");
  if (fp) {
    int counter = 0;
    while (!feof(fp) && !ferror(fp)) {
      ++counter;
      (void)fgetc(fp);
    }
    fclose(fp);
    printf("Number of characters read: %d\n", counter);
  }
}

 
// Contents of text_file.txt
This has
CRLF newlines
in it.

If you save the contents of text_file.txt with Windows line endings (CRLF) and run the program on Windows, it will print 30. However, if you compile the application on a platform which does not use CRLF as its line endings, it will print 32. This is because MSVC's text translation mode will translate the CRLF characters into a single LF character on input, and translate a single LF character to CRLF on output. To ensure consistent behavior between platforms, consider opening the file in binary translation mode explicitly.

Compliant code
#include <stdio.h>
 
void func( void ) {
  FILE *fp = fopen("text_file.txt", "rb");
  if (fp) {
    int counter = 0;
    while (!feof(fp) && !ferror(fp)) {
      ++counter;
      (void)fgetc(fp);
    }
    fclose(fp);
    printf("Number of characters read: %d\n", counter);
  }
}

This program will print 32 with the given text, regardless of platform.

Risk Assessment

Rule Severity Likelihood Detectable Repairable Priority Level
MSC23-C High Probable No No P6 L3

Automated Detection

Tool

Version

Checker

Description

Astrée
25.10

Supported: Astrée reports non-standard language elements.
CodeSonar
9.1p0

BADFUNC.*
CONCURRENCY.C_ATOMIC
CONCURRENCY.THREADLOCAL
LANG.FUNCS.NORETURN
LANG.PREPROC.INCL.TGMATH_H
LANG.STRUCT.ALIGNAS
LANG.STRUCT.ALIGNAS.EZA
LANG.STRUCT.ALIGNAS.IAS
LANG.STRUCT.ALIGNAS.TMAS
LANG.STRUCT.ALIGNOF
LANG.STRUCT.DECL.IMPFN
LANG.STRUCT.DECL.VLA
LANG.STRUCT.INIT.UADI
LANG.TYPE.VMAT
MATH.RANGE.GAMMA

Many checks for uses of functions that have vendor-specific differences
Use of C Atomic
Use of Thread Local
Use of Noreturn
Use of <tgmath.h>
Use of Alignas
Explicit Zero Alignment
Inconsistent Alignment Specifications
Too Many Alignment Specifiers
Use of Alignof
Implicit Function Declaration
Declaration of Variable Length Array
Unspecified Array Size with Designator Initialization
Pointer to Variably-modified Array Type
Gamma on Zero

Helix QAC

2025.2

C3375