diff --git a/src/Variable.cpp b/src/Variable.cpp index 0295b27ac..adcdb5158 100644 --- a/src/Variable.cpp +++ b/src/Variable.cpp @@ -570,6 +570,29 @@ Variable::is_const_after_deref(int deref_level) const return false; } +bool +Variable::is_partial_volatile_after_deref(int deref_level) const +{ + if (deref_level < 0) { + return false; + } + // check if the whole struct/union type is volatile + if (qfer.is_volatile_after_deref(deref_level)) { + return false; + } + if (type) { + // check individual fields + int i; + const Type* t = type; + for (i = 0; i < deref_level; i++) { + t = t->ptr_type; + } + assert(t); + return t->is_volatile_struct_union(); + } + return false; +} + bool Variable::is_volatile_after_deref(int deref_level) const { diff --git a/src/Variable.h b/src/Variable.h index 40a68d5dc..8f957d85c 100644 --- a/src/Variable.h +++ b/src/Variable.h @@ -86,6 +86,7 @@ class Variable bool is_volatile(void) const; bool is_access_once(void) const { return isAccessOnce; } bool is_const_after_deref(int deref_level) const; + bool is_partial_volatile_after_deref(int deref_level) const; bool is_volatile_after_deref(int deref_level) const; bool is_packed_aggregate_field_var() const; bool has_field_var(const Variable* v) const; diff --git a/src/VariableSelector.cpp b/src/VariableSelector.cpp index 02ef82ab1..173444072 100644 --- a/src/VariableSelector.cpp +++ b/src/VariableSelector.cpp @@ -244,6 +244,14 @@ VariableSelector::is_eligible_var(const Variable* var, int deref_level, Effect:: } var = coll; } + + // Partial volatile variables are struct/union containing a + // volatile field. Reading/writing them through pointers is + // problematic. See issue #74 for details. + if (deref_level > 0 && var->is_partial_volatile_after_deref(deref_level)) { + return false; + } + const Effect &effect_context = cg_context.get_effect_context(); bool is_const = var->is_const_after_deref(deref_level); bool is_volatile = var->is_volatile_after_deref(deref_level) || var->is_volatile();