summaryrefslogtreecommitdiffstats
path: root/player/loadfile.c
diff options
context:
space:
mode:
authorDudemanguy <random342@airmail.cc>2023-08-14 14:13:02 -0500
committerDudemanguy <random342@airmail.cc>2023-08-16 13:01:28 +0000
commit0b4a36476d0efcb4715a56c6e6de241af9a4b9ec (patch)
treec9de7619cb191d1aab5a66ce3e0c969a9f62cec2 /player/loadfile.c
parentf19bafc0e442dedf3573e92e1cd4ef332217924d (diff)
downloadmpv-0b4a36476d0efcb4715a56c6e6de241af9a4b9ec.tar.bz2
mpv-0b4a36476d0efcb4715a56c6e6de241af9a4b9ec.tar.xz
loadfile: avoid infinite playlist loading loops
There are a number of ways one can craft a playlist file that refers to itself or cleverly goes around in a loop to other playlist files. There is obviously no use for this, but mpv spins around forever trying to load the files so you have to just SIGTERM/SIGKILL it. We can be smarter about this and attempt to detect it. The condition for detecting this is surprisingly simple: the filename of the first entry in the playlist must match a previous playlist path we stored. If we get this, we can then log an error and stop playback. If there is a "real" file loaded at any point in time, then we know it's not an infinite loop and clear out the saved playlist paths. Fixes #3967.
Diffstat (limited to 'player/loadfile.c')
-rw-r--r--player/loadfile.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/player/loadfile.c b/player/loadfile.c
index a2f593333e..d558ad6930 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -1309,6 +1309,28 @@ void prefetch_next(struct MPContext *mpctx)
}
}
+static void clear_playlist_paths(struct MPContext *mpctx)
+{
+ TA_FREEP(&mpctx->playlist_paths);
+ mpctx->playlist_paths_len = 0;
+}
+
+static bool infinite_playlist_loading_loop(struct MPContext *mpctx, struct playlist *pl)
+{
+ if (pl->num_entries) {
+ struct playlist_entry *e = pl->entries[0];
+ for (int n = 0; n < mpctx->playlist_paths_len; n++) {
+ if (strcmp(mpctx->playlist_paths[n], e->filename) == 0) {
+ clear_playlist_paths(mpctx);
+ return true;
+ }
+ }
+ }
+ MP_TARRAY_APPEND(mpctx, mpctx->playlist_paths, mpctx->playlist_paths_len,
+ talloc_strdup(mpctx->playlist_paths, mpctx->filename));
+ return false;
+}
+
// Destroy the complex filter, and remove the references to the filter pads.
// (Call cleanup_deassociated_complex_filters() to close decoders/VO/AO
// that are not connected anymore due to this.)
@@ -1660,6 +1682,11 @@ static void play_current_file(struct MPContext *mpctx)
mp_delete_watch_later_conf(mpctx, mpctx->filename);
struct playlist *pl = mpctx->demuxer->playlist;
playlist_populate_playlist_path(pl, mpctx->filename);
+ if (infinite_playlist_loading_loop(mpctx, pl)) {
+ mpctx->stop_play = PT_STOP;
+ MP_ERR(mpctx, "Infinite playlist loading loop detected.\n");
+ goto terminate_playback;
+ }
transfer_playlist(mpctx, pl, &end_event.playlist_insert_id,
&end_event.playlist_insert_num_entries);
mp_notify_property(mpctx, "playlist");
@@ -1766,6 +1793,7 @@ static void play_current_file(struct MPContext *mpctx)
mpctx->playback_initialized = true;
mp_notify(mpctx, MPV_EVENT_FILE_LOADED, NULL);
update_screensaver_state(mpctx);
+ clear_playlist_paths(mpctx);
if (watch_later)
mp_delete_watch_later_conf(mpctx, mpctx->filename);