https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117315
--- Comment #17 from Sam James <sjames at gcc dot gnu.org> --- Looking at trunk. LHS (-) is with malloc attribute (-> crashes), RHS (+) is without (-> works). In local-pure-const, we get: ``` --- a/libwsutil.so-wmem_tree.c.054t.local-pure-const1 +++ b/libwsutil.so-wmem_tree.c.054t.local-pure-const1 [...] @@ -596,13 +596,13 @@ Pass statistics of "local-pure-const": ---------------- scanning: wmem_register_callback (data_scope_7(D), wmem_tree_reset_cb, tree_6); checking flags for call: neither scanning: return tree_6; - checking previously known:Function is locally looping. -Function is locally malloc. + checking previously known: +wmem_tree_new_autoreset/13 is not a malloc candidate, reason: Return value has uses outside return stmt and comparisons against 0. +Function is locally looping. ``` We have: ``` * malloc_candidate_p() checks if FUN can possibly be annotated with malloc attribute. Currently this function does a very conservative analysis. FUN is considered to be a candidate if 1) It returns a value of pointer type. 2) SSA_NAME_DEF_STMT (return_value) is either a function call or a phi, and element of phi is either NULL or SSA_NAME_DEF_STMT(element) is function call. 3) The return-value has immediate uses only within comparisons (gcond or gassign) and return_stmt (and likewise a phi arg has immediate use only within comparison or the phi stmt). */ #define DUMP_AND_RETURN(reason) \ { \ if (dump_file && (dump_flags & TDF_DETAILS)) \ fprintf (dump_file, "\n%s is not a malloc candidate, reason: %s\n", \ (node->dump_name ()), (reason)); \ return false; \ } ``` Fine, that's not because it's clearly unsuitable for malloc, it's just being cautious. ealias is where everything diverges: ``` --- a/wmem_test-wmem_test.c.040t.ealias +++ b/wmem_test-wmem_test.c.040t.ealias @@ -44,154 +44,155 @@ CALLUSED(20) = callarg(23) CALLCLOBBERED(21) = callarg(23) callescape(19) = callarg(23) ESCAPED = extra_allocator_10 -HEAP(25) = &NONLOCAL -tree_12 = &HEAP(25) +tree_12 = NONLOCAL +tree_12 = callarg(22) +tree_12 = callarg(23) i.0_1 = i_4 -callescape(29) = NONLOCAL -CALLUSED(30) = callescape(29) -callarg(32) = tree_12 +callescape(28) = NONLOCAL +CALLUSED(29) = callescape(28) +callarg(31) = tree_12 +callarg(31) = callarg(31) + UNKNOWN +callarg(31) = *callarg(31) + UNKNOWN +CALLUSED(29) = callarg(31) +*callarg(31) = callescape(28) +CALLCLOBBERED(30) = callarg(31) +callescape(28) = callarg(31) +ESCAPED = tree_12 +callarg(32) = i.0_1 [... loads more ...] Collapsing static cycles and doing variable substitution @@ -205,76 +206,75 @@ Equivalence classes for indirect node id 5 "NONLOCAL": pointer 4, location 5 Equivalence classes for indirect node id 6 "ESCAPED_RETURN": pointer 14, location 0 Equivalence classes for direct node id 7 "STOREDANYTHING": pointer 0, location 0 Equivalence classes for indirect node id 8 "INTEGER": pointer 15, location 0 -Equivalence classes for indirect node id 9 "HEAP(25)": pointer 16, location 6 -Equivalence classes for direct node id 10 "wmem_allocator_new": pointer 0, location 0 -Equivalence classes for direct node id 11 "callescape(10)": pointer 4, location 0 -Equivalence classes for direct node id 12 "CALLUSED(11)": pointer 4, location 0 -Equivalence classes for direct node id 13 "CALLCLOBBERED(12)": pointer 0, location 0 -Equivalence classes for direct node id 14 "allocator_8": pointer 4, location 0 -Equivalence classes for direct node id 15 "callescape(14)": pointer 4, location 0 -Equivalence classes for direct node id 16 "CALLUSED(15)": pointer 4, location 0 -Equivalence classes for direct node id 17 "CALLCLOBBERED(16)": pointer 0, location 0 -Equivalence classes for direct node id 18 "extra_allocator_10": pointer 4, location 0 -Equivalence classes for direct node id 19 "wmem_tree_new_autoreset": pointer 0, location 0 -Equivalence classes for direct node id 20 "callescape(19)": pointer 19, location 0 -Equivalence classes for direct node id 21 "CALLUSED(20)": pointer 19, location 0 -Equivalence classes for direct node id 22 "CALLCLOBBERED(21)": pointer 19, location 0 -Equivalence classes for indirect node id 23 "callarg(22)": pointer 17, location 0 [... loads more ...] +Equivalence classes for direct node id 9 "wmem_allocator_new": pointer 0, location 0 +Equivalence classes for direct node id 10 "callescape(10)": pointer 4, location 0 +Equivalence classes for direct node id 11 "CALLUSED(11)": pointer 4, location 0 +Equivalence classes for direct node id 12 "CALLCLOBBERED(12)": pointer 0, location 0 +Equivalence classes for direct node id 13 "allocator_8": pointer 4, location 0 +Equivalence classes for direct node id 14 "callescape(14)": pointer 4, location 0 +Equivalence classes for direct node id 15 "CALLUSED(15)": pointer 4, location 0 +Equivalence classes for direct node id 16 "CALLCLOBBERED(16)": pointer 0, location 0 +Equivalence classes for direct node id 17 "extra_allocator_10": pointer 4, location 0 +Equivalence classes for direct node id 18 "wmem_tree_new_autoreset": pointer 0, location 0 +Equivalence classes for direct node id 19 "callescape(19)": pointer 7, location 0 +Equivalence classes for direct node id 20 "CALLUSED(20)": pointer 7, location 0 +Equivalence classes for direct node id 21 "CALLCLOBBERED(21)": pointer 7, location 0 +Equivalence classes for indirect node id 22 "callarg(22)": pointer 5, location 0 +Equivalence classes for indirect node id 23 "callarg(23)": pointer 6, location 0 [... loads more ...] ``` Later on in there: ``` Call clobber information -ESCAPED, points-to non-local, points-to NULL, points-to const-pool, points-to vars: { D.2879 } (escaped, escaped heap) +ESCAPED, points-to non-local, points-to NULL, points-to const-pool, points-to vars: { } ESCAPED_RETURN, points-to escaped, points-to vars: { } Flow-insensitive points-to information allocator_8, points-to non-local, points-to escaped, points-to NULL, points-to vars: { } extra_allocator_10, points-to non-local, points-to escaped, points-to NULL, points-to vars: { } -tree_12, points-to NULL, points-to vars: { D.2879 } (escaped, escaped heap) +tree_12, points-to non-local, points-to escaped, points-to NULL, points-to vars: { } -Points to sets created:22 +Points to sets created:17 void wmem_test_treeD.2858 () { int iD.2863; @@ -454,7 +458,7 @@ void wmem_test_treeD.2858 () # DEBUG extra_allocatorD.2861 => extra_allocator_10 # DEBUG BEGIN_STMT # .MEM_11 = VDEF <.MEM_9> - # PT = null { D.2879 } (escaped, escaped heap) + # PT = nonlocal escaped null # USE = nonlocal escaped # CLB = nonlocal escaped tree_12 = wmem_tree_new_autoresetD.2843 (allocator_8, extra_allocator_10); [...] ``` In `alias`: ``` Flow-insensitive points-to information -tree_12, points-to NULL, points-to vars: { D.6030 } +tree_12, points-to non-local, points-to escaped, points-to NULL, points-to vars: { D.6027 D.6028 D.6029 } (escaped, escaped heap) allocator_34, points-to NULL, points-to vars: { D.6028 } (escaped, escaped heap) strict_allocator_35, points-to NULL, points-to vars: { D.6029 } (escaped, escaped heap) allocator_39, points-to NULL, points-to vars: { D.6026 } strict_allocator_40, points-to NULL, points-to vars: { D.6027 } (escaped, escaped heap) -node_44, points-to non-local, points-to escaped, points-to NULL, points-to vars: { } +node_44, points-to non-local, points-to escaped, points-to NULL, points-to vars: { D.6027 D.6028 D.6029 } (escaped, escaped heap) ``` without malloc, we figure out that `strict_allocator` memory is pointed-to for `node`, which I *think* supports the https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117315#c14 theory? The dumps aren't that easy to follow though, the testcase isn't huge but it's not as simple as it could be (it tries to iterate over the tree still and so on).