This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository efl.
View the commit online.
commit 274841970ca4e02e4dba351c049f61727c8913f9
Author: Bernhard M. Wiedemann <[email protected]>
AuthorDate: Thu Aug 27 07:55:14 2026 +0200
edje_cc: drop merged-away descriptions with _part_desc_free
When a state is declared twice, _part_description_state_update() merges
the second declaration into the first and drops the description it no
longer needs. It drops it with a bare free(). These are the only two
places in edje_cc_handlers.c that release a part description without
going through _part_desc_free(), and both leave dangling references
behind.
1) desc_hash
desc_hash maps a part description pointer to the part that owns it. It
is created once per edje_cc run and never emptied, so the key of a
merged-away description stays behind. malloc hands the same address out
again for a later description, and eina_hash_add() does not replace an
existing key, so desc_hash ends up holding two entries for one key.
st_collections_group_parts_part_description_inherit() uses that hash to
find the part owning the parent description, and returns early - without
copying any type specific data - when that part is of a different type.
A stale key makes the lookup return the wrong part, and the inherited
type specific data is then silently dropped.
In the default theme this loses the
params.string: "label" "Back";
of the EXTERNAL part "back" in elm/layout/application/toolbar-content-back,
which inherits it from elm/layout/application/content-back.
2) part lookups
part_dest_lookup and part_pc_dest_lookup are keyed on the address of the
field to patch up, such as &ed->rel1.id_x. A description can have those
queued before its state is named, as in
description {
rel1.to: "other";
state: "clicked" 0.0;
}
and the bare free() then leaves them pointing into freed memory, for
data_process_lookups() to later write the resolved part id through.
_part_desc_free() removes both. Its free() of ed->state.name has to be
skipped: in the desc { "state"; } short form the name is still the token
that edje_cc_handlers_wildcard() left on the parser stack and frees
itself, so it is not the description's to release.
Whether a freed address is handed out again depends on the heap layout.
eina, ecore and edje size several pools from eina_cpu_count() during
init, well before compile() parses anything, so the same .edc compiles
to different .edj files on machines with a different number of CPUs.
Note that removing a key can only ever make the desc_hash lookup return
NULL, which is the safe path: inherit then copies the type specific data
instead of skipping it. The deliberate lookup in _part_type_set(), which
installs a dummy part of an incompatible type to force the early return,
keeps working - and stops being at risk of reading the dummy back after
it has been freed, which duplicate keys could previously cause.
See https://reproducible-builds.org/ for why this matters.
This patch was done while working on reproducible builds for openSUSE.
---
src/bin/edje/edje_cc_handlers.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/bin/edje/edje_cc_handlers.c b/src/bin/edje/edje_cc_handlers.c
index ac4be862a6..09202e6bf4 100644
--- a/src/bin/edje/edje_cc_handlers.c
+++ b/src/bin/edje/edje_cc_handlers.c
@@ -8636,6 +8636,7 @@ static void
_part_description_state_update(Edje_Part_Description_Common *ed)
{
Edje_Part *ep = current_part;
+ Edje_Part_Collection *pc = eina_list_data_get(eina_list_last(edje_collections));
if (ed == ep->default_desc) return;
if ((ep->default_desc->state.name && !strcmp(ed->state.name, ep->default_desc->state.name) && EINA_DBL_EQ(ed->state.value, ep->default_desc->state.value)) ||
@@ -8644,7 +8645,10 @@ _part_description_state_update(Edje_Part_Description_Common *ed)
if (ep->type == EDJE_PART_TYPE_IMAGE)
_edje_part_description_image_remove((Edje_Part_Description_Image *)ed);
- free(ed);
+ /* state.name is owned by the parser stack in the desc { "state"; }
+ * short form, edje_cc_handlers_wildcard() frees it there */
+ ed->state.name = NULL;
+ _part_desc_free(pc, ep, ed);
ep->other.desc_count--;
ep->other.desc = realloc(ep->other.desc,
sizeof (Edje_Part_Description_Common *) * ep->other.desc_count);
@@ -8660,7 +8664,8 @@ _part_description_state_update(Edje_Part_Description_Common *ed)
if (ep->type == EDJE_PART_TYPE_IMAGE)
_edje_part_description_image_remove((Edje_Part_Description_Image *)ed);
- free(ed);
+ ed->state.name = NULL;
+ _part_desc_free(pc, ep, ed);
ep->other.desc_count--;
ep->other.desc = realloc(ep->other.desc,
sizeof (Edje_Part_Description_Common *) * ep->other.desc_count);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.