From 26dc1953d74a81edba1d5570d3e43fb6ea752fd0 Mon Sep 17 00:00:00 2001 From: "Perneel, Luc" Date: Tue, 28 Nov 2017 17:37:45 +0100 Subject: [PATCH] Modes handling: fix memory leak on xrandr usage. In Xorg there is a memory leak each time xrandr is used. This is easy to test by issuing following command: $ while true ; do xrandr --verbose > /dev/null ; done This will gradually let X take more memory until the oom killer pops in. Reason is that each time the Monitor->Modes list grows, without pruning duplicates. This patch fixes this. An alternative solution could be to cleanup the list before retrieving a new one (instead of attaching both). --- hw/xfree86/common/xf86Config.c | 23 ++--------------------- hw/xfree86/common/xf86str.h | 1 - hw/xfree86/modes/xf86EdidModes.c | 20 +++++--------------- 3 files changed, 7 insertions(+), 37 deletions(-) diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c index 21daf1a..a6181a1 100644 --- a/hw/xfree86/common/xf86Config.c +++ b/hw/xfree86/common/xf86Config.c @@ -1936,7 +1936,7 @@ static Bool configMonitor(MonPtr monitorp, XF86ConfMonitorPtr conf_monitor) { int count; - DisplayModePtr mode, last = NULL; + DisplayModePtr mode; XF86ConfModeLinePtr cmodep; XF86ConfModesPtr modes; XF86ConfModesLinkPtr modeslnk = conf_monitor->mon_modes_sect_lst; @@ -1949,7 +1949,6 @@ configMonitor(MonPtr monitorp, XF86ConfMonitorPtr conf_monitor) monitorp->vendor = conf_monitor->mon_vendor; monitorp->model = conf_monitor->mon_modelname; monitorp->Modes = NULL; - monitorp->Last = NULL; monitorp->gamma = zeros; monitorp->widthmm = conf_monitor->mon_width; monitorp->heightmm = conf_monitor->mon_height; @@ -2018,24 +2017,9 @@ configMonitor(MonPtr monitorp, XF86ConfMonitorPtr conf_monitor) mode->HSkew = cmodep->ml_hskew; mode->VScan = cmodep->ml_vscan; mode->name = xnfstrdup(cmodep->ml_identifier); - if (last) { - mode->prev = last; - last->next = mode; - } - else { - /* - * this is the first mode - */ - monitorp->Modes = mode; - mode->prev = NULL; - } - last = mode; + monitorp->Modes = xf86ModesAdd( monitorp->Modes, mode); cmodep = (XF86ConfModeLinePtr) cmodep->list.next; } - if (last) { - last->next = NULL; - } - monitorp->Last = last; /* add the (VESA) default modes */ if (!addDefaultModes(monitorp)) @@ -2315,20 +2299,17 @@ static Bool addDefaultModes(MonPtr monitorp) { DisplayModePtr mode; - DisplayModePtr last = monitorp->Last; int i = 0; for (i = 0; i < xf86NumDefaultModes; i++) { mode = xf86DuplicateMode(&xf86DefaultModes[i]); if (!modeIsPresent(mode, monitorp)) { monitorp->Modes = xf86ModesAdd(monitorp->Modes, mode); - last = mode; } else { free(mode); } } - monitorp->Last = last; return TRUE; } diff --git a/hw/xfree86/common/xf86str.h b/hw/xfree86/common/xf86str.h index bfcb75e..1c083c7 100644 --- a/hw/xfree86/common/xf86str.h +++ b/hw/xfree86/common/xf86str.h @@ -131,7 +131,6 @@ typedef struct { int nVrefresh; range vrefresh[MAX_VREFRESH]; DisplayModePtr Modes; /* Start of the monitor's mode list */ - DisplayModePtr Last; /* End of the monitor's mode list */ Gamma gamma; /* Gamma of the monitor */ int widthmm; int heightmm; diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c index f0e1e97..261ff8a 100644 --- a/hw/xfree86/modes/xf86EdidModes.c +++ b/hw/xfree86/modes/xf86EdidModes.c @@ -1198,21 +1198,11 @@ xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC) if (!Monitor->nHsync || !Monitor->nVrefresh) DDCGuessRangesFromModes(scrnIndex, Monitor, Modes); - /* look for last Mode */ - Mode = Modes; - - while (Mode->next) - Mode = Mode->next; - /* add to MonPtr */ - if (Monitor->Modes) { - Monitor->Last->next = Modes; - Modes->prev = Monitor->Last; - Monitor->Last = Mode; - } - else { - Monitor->Modes = Modes; - Monitor->Last = Mode; - } + Monitor->Modes = xf86ModesAdd( Monitor->Modes, Modes); + + /* prune doubles: otherwise this list will grow ad infinitum + until out of memory.... */ + xf86PruneDuplicateModes(Monitor->Modes); } } -- 2.1.4