eo: fix UB in the eo event code (edje_cc hangs etc.)

Today I started experiencing mysterious hanging of edje_cc
during build. "The French are at it again" I thought, and
after spending a while bisecting, I found the culprit.
It's 7f53d91583.

So, what is happening in here?

The idea here was fundamentally sound; compute a special
hash value for event descriptors, taking range between 0
and 63 (on 64-bit systems) and 0 and 31 (on 32-bit systems),
then use a mask sized 32-bit or 64-bit (depending on your
system) and check early if to bail out from callback_call,
saving some resources. So far so good.

The problem is in the way the mask is handled. We're applying
the hash as the shift value like, `x |= (1 << hash)`. On 32-bit
systems this is okay, but on 64-bit systems, C's dumb silent
coercion rules kick in, since the left side of the expression
is 1, a literal with type signed int; that means our shifting
range is limited to 31 and what we get is... undefined behavior.

This is obviously not what we want, so take a 1ULL value as a
base. The previous thing seemingly worked on x86_64 (nobody
reported any issues) and interestingly it worked for me too
for a while (on ppc64le), but undefined behavior can be
unpredictable, so...

This shouldn't need a commit message as long as this, but I'm
making it proportional to the amount of time I wasted on this.
This commit is contained in:
Daniel Kolesa 2019-11-14 04:02:09 +01:00
parent 288218527d
commit 9ca573f40f
1 changed files with 2 additions and 2 deletions

View File

@ -1263,7 +1263,7 @@ _special_event_count_inc(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Arr
event_hash = _pointer_hash((uintptr_t) it->desc);
pd->callbacks_mask |= 1 << event_hash;
pd->callbacks_mask |= 1ULL << event_hash;
EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_CALLBACK_ADD)
else EFL_OBJECT_EVENT_CB_INC(obj_id, it, pd, EFL_EVENT_CALLBACK_DEL)
@ -2009,7 +2009,7 @@ _event_callback_call(Eo *obj_id, Efl_Object_Data *pd,
if (!legacy_compare)
{
event_hash = _pointer_hash((uintptr_t) desc);
if (!(pd->callbacks_mask & (1 << event_hash)))
if (!(pd->callbacks_mask & (1ULL << event_hash)))
return EINA_TRUE;
}