Inside Bit fields allow for a simple way to break portions of a struct
you may define a bit field any way that you want, however when compiling on different compilers the results of the bitfield layout may vary. It is implementation defined as to whether or not the bit field has a lo-hi or hi-lo ordering of bits.
In the following code, despite using a mutex to lock the flag bit defined in the foo struct, it is in general impossible to load the flag and counter fields seperatly, thus a mutex would have to be used when accessing either field in the struct in order for it to be thread safe. In addition, in the code below, it is implementation defined as to if flag and counter are signed or unsigned ints.
Code
into portions that only use up a certain specified number of bits. If multiple threads are accessing or making modifications to different bit fields, a race condition may be present because the architecture may not be able to modify only the bits to which the currently being modified member may refer. Therefore, a mutex protecting all bit fields at the same time must be used.
Non-Compliant Code Example
In the following non-compliant code, two threads presumed to be running simultaneously access two separate members of a global struct
.
Code Block | ||
---|---|---|
| ||
struct multi_threaded_flags {
int flag1 : 2;
int flag2 : 2;
};
struct multi_threaded_flags flags;
void thread1() {
flags.flag1 = 1;
}
void thread2() {
flags.flag2 = 2;
}
|
Although this appears to be harmless, it is possible (and likely) that the architecture that this is running on has aligned flag1
and flag2
on the same byte. If both assignments occur on a thread scheduling interleaving which ends with the both stores occurring after one another, it is possible that only one of the flags will be set as intended and the other flag will equal its previous value due to the fact that both of the bit fields fell on the same byte, which was the smallest unit the processor could work on.
Compliant Solution
This compliant solution protects all usage of the flags with a mutex, preventing an unfortunate thread scheduling interleaving from being able to occur.
Code Block | ||
---|---|---|
| ||
struct multi_threaded_flags {
int flag1 : 2;
int flag2 : 2;
pthread_mutex_t mutex | ||
Code Block | ||
| ||
struct foo { int flag : 1; int counter : 15; }; struct foo my_foo; ... multi_threaded_flags flags; void thread1() { pthread_mutex_lock(&my_flags.mutex); my_foo.flag flags.flag1 = !my_foo.flag; 1; pthread_mutex_unlock(&flags.mutex); } void thread2() { pthread_mutex_unlocklock(&my_flags.mutex); my_foo.counter++; |
...
flags.flag2 = 2;
pthread_mutex_unlock(&flags.mutex);
}
|
Risk Assessment
Although the race window is very narrow, having an assignment or an expression evaluate improperly due to misinterpreted data can cause a program to misbehave, possibly resulting in a corrupted running state.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
INT | 2 (medium) | 1 2 (probable) | 1 2 (medium) | P8 | P2 L6 L3 |
References
Wiki Markup |
---|
*Sources:* [http://en.wikipedia.org/wiki/Bit_field] [http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf] \[\[[ISO/IEC 9899-1999:TC2|AA. C References#ISO/IEC 9899-1999TC2]\] Section 6.7.2.1\], "Structure and union specifiers" |