sna: CustomEDID fix

For my HTPC setup, I'm using the option "CustomEDID".
With this option, output attaching and destroying events leads to
crashes.

The following sequence leads to a crash:
- In xorg.conf: Option "CustomEDID" "HDMI2:/etc/my_edid.bin"
- Starting Xorg
- Connect HDMI2
- Disconnect HDMI2
- Reconnect HDMI2
  -> Crash

The crash happens in xf86OutputSetEDID
(xorg/xserver/hw/xfree86/modes/xf86Crtc.c)
at "free(output->MonInfo)". MonInfo is assigned with
sna_output->fake_edid_mon
which is allocated by intel driver in sna_output_load_fake_edid
(src/sna/sna_display.c).

Sequence details:
- Starting Xorg
   -> fake_edid_mon is initialized

- Connect HDMI2
   -> xf86OutputSetEDID is called:
       - MonInfo is NULL
       - MonInfo is assigned with fake_edid_mon pointer
       - MonInfo is read by Xorg

- Disconnect HDMI2

- Reconnect HDMI2
   -> xf86OutputSetEDID is called:
       - MonInfo is freed thus also fake_edid_mon
       - MonInfo is assigned with fake_edid_mon
       - MonInfo is read but it was freed -> CRASH

The fix consists of a new instance of xf86MonPtr for each calls of
xf86OutputSetEDID.
is initialized with fake_edid_raw which render
fake_edid_mon useless.
With this proposal, the behaviour of an EDID override is similar to
a "real" EDID.

Signed-off-by: Dominique Constant <dom.constant@free.fr>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
dom.constant@free.fr 2018-02-06 19:57:05 +01:00 committed by Chris Wilson
parent 9b4f400190
commit aa36399cca
1 changed files with 12 additions and 16 deletions

View File

@ -267,7 +267,6 @@ struct sna_output {
uint32_t edid_blob_id;
uint32_t edid_len;
void *edid_raw;
xf86MonPtr fake_edid_mon;
void *fake_edid_raw;
bool has_panel_limits;
@ -4189,13 +4188,21 @@ static DisplayModePtr
sna_output_override_edid(xf86OutputPtr output)
{
struct sna_output *sna_output = output->driver_private;
xf86MonPtr mon = NULL;
if (sna_output->fake_edid_mon == NULL)
if (sna_output->fake_edid_raw == NULL)
return NULL;
xf86OutputSetEDID(output, sna_output->fake_edid_mon);
return xf86DDCGetModes(output->scrn->scrnIndex,
sna_output->fake_edid_mon);
mon = xf86InterpretEDID(output->scrn->scrnIndex, sna_output->fake_edid_raw);
if (mon == NULL) {
return NULL;
}
mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
xf86OutputSetEDID(output, mon);
return xf86DDCGetModes(output->scrn->scrnIndex, mon);
}
static DisplayModePtr
@ -4983,7 +4990,6 @@ sna_output_load_fake_edid(xf86OutputPtr output)
FILE *file;
void *raw;
int size;
xf86MonPtr mon;
filename = fake_edid_name(output);
if (filename == NULL)
@ -5015,16 +5021,6 @@ sna_output_load_fake_edid(xf86OutputPtr output)
}
fclose(file);
mon = xf86InterpretEDID(output->scrn->scrnIndex, raw);
if (mon == NULL) {
free(raw);
goto err;
}
if (mon && size > 128)
mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
sna_output->fake_edid_mon = mon;
sna_output->fake_edid_raw = raw;
xf86DrvMsg(output->scrn->scrnIndex, X_CONFIG,