You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 118 Next »

The C Standard, 6.7.3.2, discusses the layout of structure fields. It specifies that non-bit-field members are aligned in an implementation-defined manner and that there may be padding within or at the end of a structure. Furthermore, initializing the members of the structure does not guarantee initialization of the padding bytes. The C Standard, 6.2.6.1, paragraph 6 [ISO/IEC 9899:2024], states

When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values (e.g. structure and union assignment may or may not copy any padding bits). 

Additionally, the storage units in which a bit-field resides may also have padding bits. For an object with automatic storage duration, these padding bits do not take on specific values and can contribute to leaking sensitive information.

When passing a pointer to a structure across a trust boundary to a different trusted domain, the programmer must ensure that the padding bytes and bit-field storage unit padding bits of such a structure do not contain sensitive information.

Noncompliant Code Example

This noncompliant code example runs in kernel space and copies data from arg to user space. However, padding bytes may be used within the structure, for example, to ensure the proper alignment of the structure members. These padding bytes may contain sensitive information, which may then be leaked when the data is copied to user space.

#include <stddef.h>

struct test {
  int a;
  char b;
  int c;
};

/* Safely copy bytes to user space */
extern int copy_to_user(void *dest, void *src, size_t size);

void do_stuff(void *usr_buf) {
  struct test arg = {.a = 1, .b = 2, .c = 3};
  copy_to_user(usr_buf, &arg, sizeof(arg));
}

Noncompliant Code Example (memset())

The padding bytes can be explicitly initialized by calling memset():

#include <string.h>

struct test {
  int a;
  char b;
  int c;
};

/* Safely copy bytes to user space */
extern int copy_to_user(void *dest, void *src, size_t size);

void do_stuff(void *usr_buf) {
  struct test arg;

  /* Set all bytes (including padding bytes) to zero */
  memset(&arg, 0, sizeof(arg));

  arg.a = 1;
  arg.b = 2;
  arg.c = 3;

  copy_to_user(usr_buf, &arg, sizeof(arg));
}

However, a conforming compiler is free to implement arg.b = 2 by setting the low-order bits of a register to 2, leaving the high-order bits unchanged and containing sensitive information. Then the platform copies all register bits into memory, leaving sensitive information in the padding bits. Consequently, this implementation could leak the high-order bits from the register to a user.

Compliant Solution

This compliant solution serializes the structure data before copying it to an untrusted context:

#include <stddef.h>
#include <string.h>
 
struct test {
  int a;
  char b;
  int c;
};
 
/* Safely copy bytes to user space */
extern int copy_to_user(void *dest, void *src, size_t size);
 
void do_stuff(void *usr_buf) {
  struct test arg = {.a = 1, .b = 2, .c = 3};
  /* May be larger than strictly needed */
  unsigned char buf[sizeof(arg)];
  size_t offset = 0;
  
  memcpy(buf + offset, &arg.a, sizeof(arg.a));
  offset += sizeof(arg.a);
  memcpy(buf + offset, &arg.b, sizeof(arg.b));
  offset += sizeof(arg.b);
  memcpy(buf + offset, &arg.c, sizeof(arg.c));
  offset += sizeof(arg.c);
  /* Set all remaining bytes to zero */
  memset(buf + offset, 0, sizeof(arg) - offset);

  copy_to_user(usr_buf, buf, offset /* size of info copied */);
} 

This code ensures that no uninitialized padding bytes are copied to unprivileged users. Important: The structure copied to user space is now a packed structure and the copy_to_user() function (or other eventual user) would need to unpack it to recreate the original padded structure.

Compliant Solution (Padding Bytes)

Padding bytes can be explicitly declared as fields within the structure. This solution is not portable, however, because it depends on the implementation and target memory architecture. The following solution is specific to the x86-32 architecture:

#include <assert.h>
#include <stddef.h>

struct test {
  int a;
  char b;
  char padding_1, padding_2, padding_3;
  int c;
};

/* Safely copy bytes to user space */
extern int copy_to_user(void *dest, void *src, size_t size);

void do_stuff(void *usr_buf) {
  /* Ensure c is the next byte after the last padding byte */
  static_assert(offsetof(struct test, c) ==
                offsetof(struct test, padding_3) + 1,
                "Structure contains intermediate padding");
  /* Ensure there is no trailing padding */
  static_assert(sizeof(struct test) ==
                offsetof(struct test, c) + sizeof(int),
                "Structure contains trailing padding");
  struct test arg = {.a = 1, .b = 2, .c = 3};
  arg.padding_1 = 0;
  arg.padding_2 = 0;
  arg.padding_3 = 0;
  copy_to_user(usr_buf, &arg, sizeof(arg));
}

The C Standard static_assert() macro accepts a constant expression and an error message. The expression is evaluated at compile time and, if false, the compilation is terminated and the error message is output. (See DCL03-C. Use a static assertion to test the value of a constant expression for more details.) The explicit insertion of the padding bytes into the struct should ensure that no additional padding bytes are added by the compiler and consequently both static assertions should be true. However, it is necessary to validate these assumptions to ensure that the solution is correct for a particular implementation.

Compliant Solution (Structure Packing—GCC)

GCC allows specifying declaration attributes using the keyword __attribute__((__packed__)). When this attribute is present, the compiler will not add padding bytes for memory alignment unless an explicit alignment specifier for a structure member requires the introduction of padding bytes.

#include <stddef.h>

struct test {
  int a;
  char b;
  int c;
} __attribute__((__packed__));

/* Safely copy bytes to user space */
extern int copy_to_user(void *dest, void *src, size_t size);

void do_stuff(void *usr_buf) {
  struct test arg = {.a = 1, .b = 2, .c = 3};
  copy_to_user(usr_buf, &arg, sizeof(arg));
}

Compliant Solution (Structure Packing—Microsoft Visual Studio)

Microsoft Visual Studio  supports #pragma pack() to suppress padding bytes [MSDN]. The compiler adds padding bytes for memory alignment, depending on the current packing mode, but still honors the alignment specified by __declspec(align()). In this compliant solution, the packing mode is set to 1 in an attempt to ensure all fields are given adjacent offsets:

#include <stddef.h>

#pragma pack(push, 1) /* 1 byte */
struct test {
  int a;
  char b;
  int c;
};
#pragma pack(pop)
 
/* Safely copy bytes to user space */
extern int copy_to_user(void *dest, void *src, size_t size);

void do_stuff(void *usr_buf) {
  struct test arg = {1, 2, 3};
  copy_to_user(usr_buf, &arg, sizeof(arg));
}

The pack pragma takes effect at the first struct declaration after the pragma is seen.

Noncompliant Code Example

This noncompliant code example also runs in kernel space and copies data from struct test to user space. However, padding bits will be used within the structure due to the bit-field member lengths not adding up to the number of bits in an unsigned object. Further, there is an unnamed bit-field that causes no further bit-fields to be packed into the same storage unit. These padding bits may contain sensitive information, which may then be leaked when the data is copied to user space. For instance, the uninitialized bits may contain a sensitive kernel space pointer value that can be trivially reconstructed by an attacker in user space.

#include <stddef.h>

struct test {
  unsigned a : 1;
  unsigned : 0;
  unsigned b : 4;
};

/* Safely copy bytes to user space */
extern int copy_to_user(void *dest, void *src, size_t size);

void do_stuff(void *usr_buf) {
  struct test arg = { .a = 1, .b = 10 };
  copy_to_user(usr_buf, &arg, sizeof(arg));
}

Compliant Solution

Padding bits can be explicitly declared, allowing the programmer to specify the value of those bits. When explicitly declaring all of the padding bits, any unnamed bit-fields of length 0 must be removed from the structure because the explicit padding bits ensure that no further bit-fields will be packed into the same storage unit.

#include <assert.h>
#include <limits.h>
#include <stddef.h>

struct test {
  unsigned a : 1;
  unsigned padding1 : sizeof(unsigned) * CHAR_BIT - 1;
  unsigned b : 4;
  unsigned padding2 : sizeof(unsigned) * CHAR_BIT - 4;
};
/* Ensure that we have added the correct number of padding bits. */
static_assert(sizeof(struct test) == sizeof(unsigned) * 2,
              "Incorrect number of padding bits for type: unsigned");

/* Safely copy bytes to user space */
extern int copy_to_user(void *dest, void *src, size_t size);

void do_stuff(void *usr_buf) {
  struct test arg = { .a = 1, .padding1 = 0, .b = 10, .padding2 = 0 };
  copy_to_user(usr_buf, &arg, sizeof(arg));
}

This solution is not portable, however, because it depends on the implementation and target memory architecture. The explicit insertion of padding bits into the struct should ensure that no additional padding bits are added by the compiler. However, it is still necessary to validate these assumptions to ensure that the solution is correct for a particular implementation. For instance, the DEC Alpha is an example of a 64-bit architecture with 32-bit integers that allocates 64 bits to a storage unit.

In addition, this solution assumes that there are no integer padding bits in an unsigned int.  The portable version of the width calculation from INT35-C. Use correct integer precisions cannot be used because the bit-field width must be an integer constant expression.

From this situation, it can be seen that special care must be taken because no solution to the bit-field padding issue will be 100% portable.

 Risk Assessment

Padding units might contain sensitive data because the C Standard allows any padding to take unspecified values. A pointer to such a structure could be passed to other functions, causing information leakage.

Rule

Severity

Likelihood

Detectable

Repairable

Priority

Level

DCL39-C

Low

Unlikely

No

Yes

P2

L3

Automated Detection

Tool

Version

Checker

Description

Astrée
24.04
function-argument-with-paddingPartially checked
Axivion Bauhaus Suite

7.2.0

CertC-DCL39Detects composite structures with padding, in particular those passed to trust boundary routines.
CodeSonar
9.1p0

MISC.PADDING.POTB

Padding Passed Across a Trust Boundary

Cppcheck Premium24.11.0


premium-cert-dcl39-c


Helix QAC

2025.2

DF4941, DF4942, DF4943

Fully implemented
Klocwork
2025.2
PORTING.STORAGE.STRUCT

Fully implemented
Parasoft C/C++test

2024.2

CERT_C-DCL39-a

A pointer to a structure should not be passed to a function that can copy data to the user space

Polyspace Bug Finder

R2025b

CERT C: Rule DCL39-CChecks for information leak via structure padding 
RuleChecker
24.04
function-argument-with-paddingPartially checked
Security Reviewer - Static Reviewer

This page was automatically generated and should not be edited.

The information on this page was provided by outside contributors and has not been verified by SEI CERT.

The table below can be re-ordered, by clicking column headers.

Tool Version: 6.02

Checker

Guideline

arithOperationsOnVoidPointer API04-C. Provide a consistent and usable error-checking mechanism
arrayIndexOutOfBoundsCond ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
assignmentInAssert ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
autoVariables ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
autovarInvalidDeallocation ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C01 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C02 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C03 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C04 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C05 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C06 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C07 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C08 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C08 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C09 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C10 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C11 CON02-C. Do not use volatile as a synchronization primitive
C12 CON05-C. Do not perform operations that can block while holding a lock
C13 DCL03-C. Use a static assertion to test the value of a constant expression
C14 DCL03-C. Use a static assertion to test the value of a constant expression
C15 DCL03-C. Use a static assertion to test the value of a constant expression
C16 DCL13-C. Declare function parameters that are pointers to values not changed by the function as const
C17 FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning call
C18 DCL30-C. Declare objects with appropriate storage durations
C19 DCL31-C. Declare identifiers before using them
C20 DCL39-C. Avoid information leakage when passing a structure across a trust boundary
C21 DCL39-C. Avoid information leakage when passing a structure across a trust boundary
C22 DCL39-C. Avoid information leakage when passing a structure across a trust boundary
C23 DCL39-C. Avoid information leakage when passing a structure across a trust boundary
C24 ARR36-C. Do not subtract or compare two pointers that do not refer to the same array
C25 DCL39-C. Avoid information leakage when passing a structure across a trust boundary
C26 DCL40-C. Do not create incompatible declarations of the same function or object
C31 ERR04-C. Choose an appropriate termination strategy
C32 ERR05-C. Application-independent code should provide error detection without dictating error handling
C33 ERR05-C. Application-independent code should provide error detection without dictating error handling
C34 ERR32-C. Do not rely on indeterminate values of errno
C37 EXP00-C. Use parentheses for precedence of operation
C38 EXP09-C. Use sizeof to determine the size of a type or variable
C39 EXP09-C. Use sizeof to determine the size of a type or variable
C40 EXP09-C. Use sizeof to determine the size of a type or variable
C42 EXP09-C. Use sizeof to determine the size of a type or variable
C44 EXP09-C. Use sizeof to determine the size of a type or variable
C45 EXP09-C. Use sizeof to determine the size of a type or variable
C46 EXP09-C. Use sizeof to determine the size of a type or variable
C46 EXP09-C. Use sizeof to determine the size of a type or variable
C47 EXP12-C. Do not ignore values returned by functions
C48 EXP12-C. Do not ignore values returned by functions
C49 ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
C50 EXP30-C. Do not depend on the order of evaluation for side effects
C50 EXP14-C. Beware of integer promotion when performing bitwise operations on integer types smaller than int
C51 EXP19-C. Use braces for the body of an if, for, or while statement
C52 DCL03-C. Use a static assertion to test the value of a constant expression
C54 EXP33-C. Do not read uninitialized memory
C55 EXP33-C. Do not read uninitialized memory
C56 EXP33-C. Do not read uninitialized memory
C57 EXP33-C. Do not read uninitialized memory
C58 EXP33-C. Do not read uninitialized memory
C59 EXP33-C. Do not read uninitialized memory
C60 EXP33-C. Do not read uninitialized memory
C61 EXP33-C. Do not read uninitialized memory
C62 EXP33-C. Do not read uninitialized memory
C63 EXP33-C. Do not read uninitialized memory
C64 EXP34-C. Do not dereference null pointers
C65 EXP34-C. Do not dereference null pointers
C66 EXP34-C. Do not dereference null pointers
C67 EXP36-C. Do not cast pointers into more strictly aligned pointer types
C68 EXP36-C. Do not cast pointers into more strictly aligned pointer types
C69 EXP36-C. Do not cast pointers into more strictly aligned pointer types
C70 EXP36-C. Do not cast pointers into more strictly aligned pointer types
C77 FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning call
C78 FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning call
C79 FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning call
C80 FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning call
C80 FIO42-C. Close files when they are no longer needed
C81 FIO47-C. Use valid format strings
C82 FIO47-C. Use valid format strings
C83 FIO47-C. Use valid format strings
C83 FIO47-C. Use valid format strings
C84 FIO47-C. Use valid format strings
C85 FIO47-C. Use valid format strings
C86 FIO47-C. Use valid format strings
C86 FIO47-C. Use valid format strings
C101 ARR32-C. Ensure size arguments for variable length arrays are in a valid range
C107 ARR36-C. Do not subtract or compare two pointers that do not refer to the same array
C109 ARR38-C. Guarantee that library functions do not form invalid pointers
C122 CON40-C. Do not refer to an atomic variable twice in an expression
C123 CON40-C. Do not refer to an atomic variable twice in an expression
C126 DCL01-C. Do not reuse variable names in subscopes
C127 DCL01-C. Do not reuse variable names in subscopes
C129 DCL03-C. Use a static assertion to test the value of a constant expression
C130 DCL03-C. Use a static assertion to test the value of a constant expression
C132 DCL03-C. Use a static assertion to test the value of a constant expression
C133 DCL03-C. Use a static assertion to test the value of a constant expression
C135 DCL03-C. Use a static assertion to test the value of a constant expression
C154 DCL03-C. Use a static assertion to test the value of a constant expression
C155 DCL03-C. Use a static assertion to test the value of a constant expression
C176 DCL30-C. Declare objects with appropriate storage durations
C177 DCL30-C. Declare objects with appropriate storage durations
C178 DCL30-C. Declare objects with appropriate storage durations
C179 DCL30-C. Declare objects with appropriate storage durations
CbOB INT02-C. Understand integer conversion rules
CconstVariable INT02-C. Understand integer conversion rules
CdLT INT02-C. Understand integer conversion rules
CdoubleFree INT02-C. Understand integer conversion rules
CduplicateCondition INT02-C. Understand integer conversion rules
CE6 INT02-C. Understand integer conversion rules
CE6_S INT02-C. Understand integer conversion rules
CE7 INT02-C. Understand integer conversion rules
CE8 MSC25-C. Do not use insecure or weak cryptographic algorithms
CE11 INT02-C. Understand integer conversion rules
CE12 INT02-C. Understand integer conversion rules
CE13 INT02-C. Understand integer conversion rules
CE256 INT02-C. Understand integer conversion rules
CfCO INT02-C. Understand integer conversion rules
CinvalidLifetime INT02-C. Understand integer conversion rules
CinvalidScanfArgType_int INT02-C. Understand integer conversion rules
CiRV INT02-C. Understand integer conversion rules
CiSFW INT02-C. Understand integer conversion rules
CknownConditionTrueFalse INT02-C. Understand integer conversion rules
ClRVNU INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data
CmAD INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data
CmemleakOnRealloc INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data
CmissingReturn INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data
CMR INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data
CmVOOR INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data
CnAS INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data
CPP_17 MEM31-C. Free dynamically allocated memory when no longer needed
CPP_18 MEM31-C. Free dynamically allocated memory when no longer needed
CPP_22 MEM31-C. Free dynamically allocated memory when no longer needed
CPP_23 MEM31-C. Free dynamically allocated memory when no longer needed
CPP_24 MEM31-C. Free dynamically allocated memory when no longer needed
CPP_25 MEM31-C. Free dynamically allocated memory when no longer needed
CPP_26 MEM31-C. Free dynamically allocated memory when no longer needed
CPP_27 MEM31-C. Free dynamically allocated memory when no longer needed
CPP_31 MEM34-C. Only free memory allocated dynamically
CPP_32 MEM34-C. Only free memory allocated dynamically
CPP_33 MEM34-C. Only free memory allocated dynamically
CPP_34 MEM34-C. Only free memory allocated dynamically
CPP_35 MEM34-C. Only free memory allocated dynamically
CPP_36 MEM34-C. Only free memory allocated dynamically
CPP_57 MSC07-C. Detect and remove dead code
CPP_58 MSC07-C. Detect and remove dead code
CPP_59 MSC07-C. Detect and remove dead code
CPP_60 MSC07-C. Detect and remove dead code
CPP_61 MSC07-C. Detect and remove dead code
CPP_62 MSC07-C. Detect and remove dead code
CPP_uninitvar MSC07-C. Detect and remove dead code
CPPCrypt MSC07-C. Detect and remove dead code
CPPDSLHardcoded MSC07-C. Detect and remove dead code
CPPDSLRAND MSC07-C. Detect and remove dead code
CPPDSLWES MSC07-C. Detect and remove dead code
CpPED MSC07-C. Detect and remove dead code
CPPEnterCriticalSection MSC07-C. Detect and remove dead code
CPPIsBadWritePtr MSC07-C. Detect and remove dead code
CPPLoadLibrary MSC07-C. Detect and remove dead code
CPPLoop MSC07-C. Detect and remove dead code
CuEV MSC24-C. Do not use deprecated or obsolescent functions
CvariableScope MSC24-C. Do not use deprecated or obsolescent functions
CWE395TEST_2_CPP MSC24-C. Do not use deprecated or obsolescent functions
CWE561P25 MSC24-C. Do not use deprecated or obsolescent functions
CwPSPPE MSC24-C. Do not use deprecated or obsolescent functions
CzDC MSC24-C. Do not use deprecated or obsolescent functions
deallocret MSC24-C. Do not use deprecated or obsolescent functions
integerOverflowCond MSC24-C. Do not use deprecated or obsolescent functions
invalidContainer MSC24-C. Do not use deprecated or obsolescent functions
invalidFunctionArg MSC24-C. Do not use deprecated or obsolescent functions
leakUnsafeArgAlloc MSC24-C. Do not use deprecated or obsolescent functions
memleak MSC24-C. Do not use deprecated or obsolescent functions
memleakOnRealloc MSC24-C. Do not use deprecated or obsolescent functions
noCopyConstructor MSC24-C. Do not use deprecated or obsolescent functions
noOperatorEq MSC24-C. Do not use deprecated or obsolescent functions
nullPointerRedundantCheck MSC24-C. Do not use deprecated or obsolescent functions
oppositeExpression MSC25-C. Do not use insecure or weak cryptographic algorithms
redundantPointerOp MSC25-C. Do not use insecure or weak cryptographic algorithms
RTOS_01 MSC25-C. Do not use insecure or weak cryptographic algorithms
RTOS_02 MSC25-C. Do not use insecure or weak cryptographic algorithms
RTOS_03 MSC25-C. Do not use insecure or weak cryptographic algorithms
RTOS_04 MSC25-C. Do not use insecure or weak cryptographic algorithms
RTOS_05 MSC25-C. Do not use insecure or weak cryptographic algorithms
RTOS_06 MSC25-C. Do not use insecure or weak cryptographic algorithms
RTOS_18 MSC25-C. Do not use insecure or weak cryptographic algorithms
RTOS_33 STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator
RTOS_34 STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator
shadowVariable STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator
shiftTooManyBits STR32-C. Do not pass a non-null-terminated character sequence to a library function that expects a string
UNSAFE_01 STR37-C. Arguments to character-handling functions must be representable as an unsigned char
UNSAFE_02 STR38-C. Do not confuse narrow and wide character strings and functions
UNSAFE_03 STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator
UNSAFE_04 STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator
UNSAFE_05 WIN02-C. Restrict privileges when spawning child processes

C20, C21,C22, C23, C25Fulli implemented

Related Vulnerabilities

Numerous vulnerabilities in the Linux Kernel have resulted from violations of this rule. CVE-2010-4083 describes a vulnerability in which the semctl() system call allows unprivileged users to read uninitialized kernel stack memory because various fields of a semid_ds struct declared on the stack are not altered or zeroed before being copied back to the user.

CVE-2010-3881 describes a vulnerability in which structure padding and reserved fields in certain data structures in QEMU-KVM were not initialized properly before being copied to user space. A privileged host user with access to /dev/kvm could use this flaw to leak kernel stack memory to user space.

CVE-2010-3477 describes a kernel information leak in act_police where incorrectly initialized structures in the traffic-control dump code may allow the disclosure of kernel memory to user space applications.

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

CERT C Secure Coding StandardDCL03-C. Use a static assertion to test the value of a constant expressionPrior to 2018-01-12: CERT: Unspecified Relationship

Bibliography

[ISO/IEC 9899:2024]6.2.6.1, "General"
6.7.3.2, "Structure and Union Specifiers"
[Graff 2003]
[Sun 1993]



  • No labels