The size of a structure is not always equal to the sum of the sizes of its members. According to Section Subclause 6.7.2.1 of the C99 standard, the C Standard states, "There may be unnamed padding within a structure object, but not at its beginning." \ [[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\9899:2011]. Wiki Markup
This is often referred to as unnamed padding is often called structure padding. Structure members are arranged in memory as they are declared in the program text. Padding may be added to the structure to ensure the structure is properly aligned in memory. Structure padding allows for faster member access on many architectures.
Rearranging the fields in a struct
can change the size of the struct
. It is possible to minimize padding anomalies if the fields are arranged in such a way that fields of the same size are grouped together.
Padding is also referred to as "Struct Member Alignment"also called struct
member alignment. Many compilers provide a flag that controls how the members of a structure are packed into memory. Modifying this flag may cause the size of the structures to vary. Most compilers also include a keyword that removes all padding; the resulting structures are referred to as are called packed structures.
Non-Compliant Code Example
Overriding the default behavior is often unwise because it leads to interface compatibility problems (the nominally same struct
has its layout interpreted differently in different modules).
Noncompliant Code Example
This noncompliant code example assumes that the size of struct buffer
is equal to the sum of the size of its individual components, which may not be the case [Dowd 2006]. The size of struct buffer
may actually be larger because of structure This non-compliant code example assumes that the size of {{struct buffer}} is equal to the {{sizeof(size_t) + (sizeof(char) * 50)}}, which may not be the case \[[Dowd|AA. C References#Dowd 06]\]. The size of {{struct buffer}} may actually be a larger due to structure padding. Wiki Markup
Code Block | ||||
---|---|---|---|---|
| ||||
enum { buffer_size = 50 }; struct buffer { size_t size; char bufferC[50buffer_size]; }; /* ... */ void func(const struct buffer *buf) { /* * Incorrectly assumingassumes sizeof(size_tstruct buffer) is 4,= * sizeof(size_t) + sizeof(char)*50 equals 54 bufferC) */ struct buffer *buf_cpy = (struct buffer *)malloc( sizeof(size_t) + (buffer_size * sizeof(char)*50) /* 1 */) ); if (buf_cpy == NULL) { /* Handle malloc() error */ } /* * withWith padding, sizeof(struct buffer) may be greater than 54 * sizeof(size_t) + sizeof(buff.bufferC), causing some data * some data to be written outside the bounds of the memory allocated. */ memcpy(buf_cpy, buf, sizeof(struct buffer)); /* ... */ free(buf_cpy); } |
Compliant Solution
Accounting for structure padding prevents these types of errors.:
Code Block | ||||
---|---|---|---|---|
| ||||
enum { buffer_size = 50 }; struct buffer { size_t size; char bufferC[50buffer_size]; }; /* ... */ void func(const struct buffer *buf) { struct buffer *buf_cpy = (struct buffer *)malloc(sizeof(struct buffer)); if (buf_cpy == NULL) { /* Handle malloc() error */ } /* ... */ memcpy(buf_cpy, buf, sizeof(struct buffer)); /* ... */ free(buf_cpy); } |
Risk Assessment
Failure to correctly determine the size of a structure can lead to subtle logic errors and incorrect calculations, the effects of which can lead to abnormal program termination, memory corruption, or execution of arbitrary code.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP03- |
2 (medium)
1 (unlikely)
1 (high)
P2
L3
C | High | Unlikely | High | P3 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| Supported: Astrée reports accesses outside the bounds of allocated memory. | |||||||
Helix QAC |
| C0697 | |||||||
LDRA tool suite |
| 578 S | Enhanced enforcement |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
...
Related Guidelines
SEI CERT C++ Coding Standard | VOID EXP03-CPP. Do not assume the size of a class or struct is the sum of the sizes of its members |
Bibliography
[Dowd 2006] | Chapter 6, "C Language Issues" ("Structure Padding," pp. 284–287) |
[ISO/IEC 9899:2011] | Subclause 6.7.2.1, |
...
"Structure |
...
and Union Specifiers" | |
[Sloss 2004] | Section 5.7, |
...
"Structure |
...
Arrangement" |
...
EXP02-A. The second operands of the logical AND and OR operators should not contain side effects 03. Expressions (EXP) EXP04-A. Do not perform byte-by-byte comparisons between structures