diff options
author | Dudemanguy <random342@airmail.cc> | 2023-08-14 14:13:02 -0500 |
---|---|---|
committer | Dudemanguy <random342@airmail.cc> | 2023-08-16 13:01:28 +0000 |
commit | 0b4a36476d0efcb4715a56c6e6de241af9a4b9ec (patch) | |
tree | c9de7619cb191d1aab5a66ce3e0c969a9f62cec2 /player/loadfile.c | |
parent | f19bafc0e442dedf3573e92e1cd4ef332217924d (diff) | |
download | mpv-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.c | 28 |
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); |