diff options
author | Chris Wilson | 2010-01-06 09:19:25 -0600 |
---|---|---|
committer | Chris Wilson | 2010-01-06 09:33:21 -0600 |
commit | d1308f4fe7f94aae51ca9f70947aea8e09597f37 (patch) | |
tree | 4db0684c9479c8cebe3003dbd4327bf8415ab197 /xf86drmMode.c | |
parent | 5dbc1b333b85695735dc5b484372758b9979b693 (diff) | |
download | libdrm-d1308f4fe7f94aae51ca9f70947aea8e09597f37.tar.gz libdrm-d1308f4fe7f94aae51ca9f70947aea8e09597f37.tar.xz libdrm-d1308f4fe7f94aae51ca9f70947aea8e09597f37.zip |
modes: Retry GETRESOURCES if a hotplug event occurs between the two ioctls
Peter Clifton hit an issue whereby he had a spurious TV hotplug event
that occurred between the two GETRESOURCES ioctls that caused the kernel
to skip filling one array and led to a crash (as the size of the
allocated and initialised block of memory differed from the reported
size).
Fixes: http://bugs.freedesktop.org/show_bug.cgi?id=25912
Crash whilst probing modes
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reported-by: Peter Clifton <pcjc2@cam.ac.uk>
Diffstat (limited to 'xf86drmMode.c')
-rw-r--r-- | xf86drmMode.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/xf86drmMode.c b/xf86drmMode.c index ca36b71b..7edc625a 100644 --- a/xf86drmMode.c +++ b/xf86drmMode.c | |||
@@ -136,14 +136,16 @@ void drmModeFreeEncoder(drmModeEncoderPtr ptr) | |||
136 | 136 | ||
137 | drmModeResPtr drmModeGetResources(int fd) | 137 | drmModeResPtr drmModeGetResources(int fd) |
138 | { | 138 | { |
139 | struct drm_mode_card_res res; | 139 | struct drm_mode_card_res res, counts; |
140 | drmModeResPtr r = 0; | 140 | drmModeResPtr r = 0; |
141 | 141 | ||
142 | retry: | ||
142 | memset(&res, 0, sizeof(struct drm_mode_card_res)); | 143 | memset(&res, 0, sizeof(struct drm_mode_card_res)); |
143 | |||
144 | if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) | 144 | if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) |
145 | return 0; | 145 | return 0; |
146 | 146 | ||
147 | counts = res; | ||
148 | |||
147 | if (res.count_fbs) | 149 | if (res.count_fbs) |
148 | res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t))); | 150 | res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t))); |
149 | if (res.count_crtcs) | 151 | if (res.count_crtcs) |
@@ -153,18 +155,31 @@ drmModeResPtr drmModeGetResources(int fd) | |||
153 | if (res.count_encoders) | 155 | if (res.count_encoders) |
154 | res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t))); | 156 | res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t))); |
155 | 157 | ||
156 | if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { | 158 | if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) |
157 | r = NULL; | ||
158 | goto err_allocs; | 159 | goto err_allocs; |
160 | |||
161 | /* The number of available connectors and etc may have changed with a | ||
162 | * hotplug event in between the ioctls, in which case the field is | ||
163 | * silently ignored by the kernel. | ||
164 | */ | ||
165 | if (counts.count_fbs < res.count_fbs || | ||
166 | counts.count_crtcs < res.count_crtcs || | ||
167 | counts.count_connectors < res.count_connectors || | ||
168 | counts.count_encoders < res.count_encoders) | ||
169 | { | ||
170 | drmFree(U642VOID(res.fb_id_ptr)); | ||
171 | drmFree(U642VOID(res.crtc_id_ptr)); | ||
172 | drmFree(U642VOID(res.connector_id_ptr)); | ||
173 | drmFree(U642VOID(res.encoder_id_ptr)); | ||
174 | |||
175 | goto retry; | ||
159 | } | 176 | } |
160 | 177 | ||
161 | /* | 178 | /* |
162 | * return | 179 | * return |
163 | */ | 180 | */ |
164 | |||
165 | |||
166 | if (!(r = drmMalloc(sizeof(*r)))) | 181 | if (!(r = drmMalloc(sizeof(*r)))) |
167 | return 0; | 182 | goto err_allocs; |
168 | 183 | ||
169 | r->min_width = res.min_width; | 184 | r->min_width = res.min_width; |
170 | r->max_width = res.max_width; | 185 | r->max_width = res.max_width; |