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.

Reply via email to