Skip to content

Commit

Permalink
fix a bug in accessing union fields
Browse files Browse the repository at this point in the history
GCC and MSVC and Clang pack structs with bit-fields differently. So if a union has a field of packed struct type, and the struct has a bit-field, writing to a field after the bit-field has non-deterministic effect, thus makes all the union fields non-readable.
  • Loading branch information
Xuejun Yang committed Aug 16, 2011
1 parent 0d755a1 commit 9a88a2f
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/FactUnion.cpp
Expand Up @@ -135,7 +135,7 @@ FactUnion::abstract_fact_for_assign(const std::vector<const Fact*>& facts, const
const FactUnion* fu = 0;
if (v->is_union_field()) {
fu = make_fact(v->field_var_of, v->get_field_id());
} else if (v->is_inside_union_field() && v->type->has_padding()) {
} else if (v->is_inside_union_field() && (v->type->has_padding() || v->is_packed_after_bitfield())) {
fu = make_fact(v->get_container_union(), BOTTOM);
}

Expand Down
9 changes: 6 additions & 3 deletions src/Type.cpp
Expand Up @@ -1207,10 +1207,13 @@ Type::is_bitfield(size_t index) const
bool
Type::has_bitfields() const
{
size_t i;
for (i = 0; i < bitfields_length_.size(); ++i) {
if (bitfields_length_[i] >= 0)
for (size_t i=0; i<fields.size(); i++) {
if (bitfields_length_[i] >= 0) {
return true;
}
if (fields[i]->eType == eStruct && fields[i]->has_bitfields()) {
return true;
}
}
return false;
}
Expand Down
19 changes: 19 additions & 0 deletions src/Variable.cpp
Expand Up @@ -1360,6 +1360,25 @@ Variable::find_pointer_fields(vector<const Variable*>& ptr_fields) const
}
}

/* a struct field packed after a bit-field could has nondeterministic offset due to incompatible packings between compilers */
bool
Variable::is_packed_after_bitfield(void) const
{
const Variable* parent = this->field_var_of;
if (parent == NULL) return false;
if (parent->type->eType == eStruct && parent->type->packed_) {
for (size_t i=0; i<parent->field_vars.size(); i++) {
if (parent->field_vars[i] == this) {
break;
}
if (parent->type->is_bitfield(i) || parent->field_vars[i]->type->has_bitfields()) {
return true;
}
}
}
return parent->is_packed_after_bitfield();
}

///////////////////////////////////////////////////////////////////////////////

// Local Variables:
Expand Down
1 change: 1 addition & 0 deletions src/Variable.h
Expand Up @@ -94,6 +94,7 @@ class Variable
int get_field_id(void) const;
bool is_union_field(void) const { return field_var_of != 0 && field_var_of->type->eType == eUnion; };
bool is_inside_union_field(void) const { return is_union_field() || (field_var_of && field_var_of->is_inside_union_field()); }
bool is_packed_after_bitfield(void) const;
bool is_array_field(void) const;
bool is_virtual(void) const;
bool is_aggregate(void) const { return type && type->is_aggregate(); }
Expand Down

0 comments on commit 9a88a2f

Please sign in to comment.