diff --git a/src/merge/cluster_helper.cpp b/src/merge/cluster_helper.cpp index b3fd34fcd..88bcf8246 100644 --- a/src/merge/cluster_helper.cpp +++ b/src/merge/cluster_helper.cpp @@ -43,6 +43,13 @@ cluster_helper_c::cluster_helper_c() } cluster_helper_c::~cluster_helper_c() { + // If rendering fails e.g. due to the file system being full, the + // cleanup code can run into access-after-free and + // free-multiple-times situations due to blocks still being present + // in the cluster. Therefore just dump them as cluster_helper_c is a + // singleton class. + if (m && m->cluster) + m->cluster->RemoveAll(); } mm_io_c * @@ -372,7 +379,7 @@ cluster_helper_c::must_duration_be_set(render_groups_c *rg, int cluster_helper_c::render() { std::vector render_groups; - KaxCues cues; + kax_cues_with_cleanup_c cues; cues.SetGlobalTimecodeScale(g_timecode_scale); bool use_simpleblock = !hack_engaged(ENGAGE_NO_SIMPLE_BLOCKS); diff --git a/src/merge/libmatroska_extensions.cpp b/src/merge/libmatroska_extensions.cpp index 9033316d2..d480ee7c1 100644 --- a/src/merge/libmatroska_extensions.cpp +++ b/src/merge/libmatroska_extensions.cpp @@ -156,3 +156,15 @@ kax_cluster_c::delete_non_blocks() { RemoveAll(); } + +kax_cues_with_cleanup_c::kax_cues_with_cleanup_c() + : KaxCues{} +{ +} + +kax_cues_with_cleanup_c::~kax_cues_with_cleanup_c() { + // If rendering fails e.g. due to the file system being full, + // libmatroska may assert() due to myTempReferences being + // non-eempty. We don't care about that assertion. + myTempReferences.clear(); +} diff --git a/src/merge/libmatroska_extensions.h b/src/merge/libmatroska_extensions.h index b7a23204f..4cd000f69 100644 --- a/src/merge/libmatroska_extensions.h +++ b/src/merge/libmatroska_extensions.h @@ -92,4 +92,10 @@ public: } }; +class kax_cues_with_cleanup_c: public KaxCues { +public: + kax_cues_with_cleanup_c(); + virtual ~kax_cues_with_cleanup_c(); +}; + #endif // MTX_LIBMATROSKA_EXTENSIONS