diff options
author | dom.constant@free.fr <dom.constant@free.fr> | 2018-02-06 19:57:05 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2018-03-02 15:17:35 +0000 |
commit | aa36399cca1250d878a4608528a535faeb0e931a (patch) | |
tree | b38ab4f73f9ad857e9fa1149ccaf30025845c675 | |
parent | 9b4f400190064f9b60f9f3ce3517586124f157ba (diff) |
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>
-rw-r--r-- | src/sna/sna_display.c | 28 |
1 files changed, 12 insertions, 16 deletions
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 091932f7..e7bf6cab 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -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_raw == NULL) + return NULL; - if (sna_output->fake_edid_mon == NULL) + mon = xf86InterpretEDID(output->scrn->scrnIndex, sna_output->fake_edid_raw); + if (mon == NULL) { return NULL; + } + + mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; + + xf86OutputSetEDID(output, mon); - xf86OutputSetEDID(output, sna_output->fake_edid_mon); - return xf86DDCGetModes(output->scrn->scrnIndex, - sna_output->fake_edid_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, |