GMainContext - Fix memory leaks and memory corruption when freeing sources while freeing a context

Merged Sebastian Dröge requested to merge sdroege/glib:main-context-freeing-of-sources into master

Instead of destroying sources directly while freeing the context, and potentially freeing them if this was the last reference to them, collect new references of all sources in a separate list before and at the same time invalidate their context so that they can't access it anymore. Only once all sources have their context invalidated, destroy them while still keeping a reference to them. Once all sources are destroyed we get rid of the additional references and free them if nothing else keeps a reference to them anymore.

This fixes a regression introduced by 26056558 in 2012.

The previous code that invalidated the context of each source and then destroyed it before going to the next source without keeping an additional reference caused memory leaks or memory corruption depending on the order of the sources in the sources lists.

If a source was destroyed it might happen that this was the last reference to this source, and it would then be freed. This would cause the finalize function to be called, which might destroy and unref another source and potentially free it. This other source would then either

  • go through the normal free logic and change the intern linked list between the sources, while other sources that are unreffed as part of the main context freeing would not. As such the list would be in an inconsistent state and we might dereference freed memory.
  • go through the normal destroy and free logic but because the context pointer was already invalidated it would simply mark the source as destroyed without actually removing it from the context. This would then cause a memory leak because the reference owned by the context is not freed.

Fixes while still keeping fixes.

Merge request reports