mirror of https://github.com/mpv-player/mpv
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.
This commit is contained in:
parent
f19bafc0e4
commit
0b4a36476d
|
@ -275,6 +275,8 @@ typedef struct MPContext {
|
||||||
struct playlist_entry *playing; // currently playing file
|
struct playlist_entry *playing; // currently playing file
|
||||||
char *filename; // immutable copy of playing->filename (or NULL)
|
char *filename; // immutable copy of playing->filename (or NULL)
|
||||||
char *stream_open_filename;
|
char *stream_open_filename;
|
||||||
|
char **playlist_paths; // used strictly for playlist validation
|
||||||
|
int playlist_paths_len;
|
||||||
enum stop_play_reason stop_play;
|
enum stop_play_reason stop_play;
|
||||||
bool playback_initialized; // playloop can be run/is running
|
bool playback_initialized; // playloop can be run/is running
|
||||||
int error_playing;
|
int error_playing;
|
||||||
|
|
|
@ -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.
|
// Destroy the complex filter, and remove the references to the filter pads.
|
||||||
// (Call cleanup_deassociated_complex_filters() to close decoders/VO/AO
|
// (Call cleanup_deassociated_complex_filters() to close decoders/VO/AO
|
||||||
// that are not connected anymore due to this.)
|
// 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);
|
mp_delete_watch_later_conf(mpctx, mpctx->filename);
|
||||||
struct playlist *pl = mpctx->demuxer->playlist;
|
struct playlist *pl = mpctx->demuxer->playlist;
|
||||||
playlist_populate_playlist_path(pl, mpctx->filename);
|
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,
|
transfer_playlist(mpctx, pl, &end_event.playlist_insert_id,
|
||||||
&end_event.playlist_insert_num_entries);
|
&end_event.playlist_insert_num_entries);
|
||||||
mp_notify_property(mpctx, "playlist");
|
mp_notify_property(mpctx, "playlist");
|
||||||
|
@ -1766,6 +1793,7 @@ static void play_current_file(struct MPContext *mpctx)
|
||||||
mpctx->playback_initialized = true;
|
mpctx->playback_initialized = true;
|
||||||
mp_notify(mpctx, MPV_EVENT_FILE_LOADED, NULL);
|
mp_notify(mpctx, MPV_EVENT_FILE_LOADED, NULL);
|
||||||
update_screensaver_state(mpctx);
|
update_screensaver_state(mpctx);
|
||||||
|
clear_playlist_paths(mpctx);
|
||||||
|
|
||||||
if (watch_later)
|
if (watch_later)
|
||||||
mp_delete_watch_later_conf(mpctx, mpctx->filename);
|
mp_delete_watch_later_conf(mpctx, mpctx->filename);
|
||||||
|
|
Loading…
Reference in New Issue