I should find all the global linked lists and systematically find out how big they are.
They always use the same UnsafeNodeGetNext/SafeNodeGetNext functions to deal with them, I can just look up all call sites for those functions and see what linked list they're being used on. then I track where that linked list is used to where someone calls a malloc
eww, the list definitely is heterogeneous. I just realized that the list always has an "end of list" marker that's just an instance of the base LinkedList struct, so it's only 8 bytes (two pointers). So every list has to contain two different types of objects, because some objects are the special end-of-list object.
one annoying detail is that I'm pretty sure this program also uses pointers to specific items in global linked lists.
which look in my disassembly just like iterating over a full list from a global head pointer.
so if I see two SafeNodeGetNext calls to addresses A and B, I assume those are two different lists. It might just be that B is a specific item in the actual global list A.