Skip to content

Commit 8e6a439

Browse files
authored
Merge pull request #366 from thesword53/decode-fix2
Fixed crashes caused by invalid concurrent writes to `drv->nextObjId`
2 parents c2860cc + bac2238 commit 8e6a439

File tree

3 files changed

+62
-62
lines changed

3 files changed

+62
-62
lines changed

src/list.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static void ensure_capacity(Array *arr, uint32_t new_capacity) {
2424
arr->buf = realloc(arr->buf, arr->capacity * sizeof(void*));
2525

2626
//clear the new part of the array
27-
memset(&arr->buf[old_capacity], 0, (arr->capacity - old_capacity) * sizeof(void*));
27+
memset(&arr->buf[old_capacity], 0, (size_t)(arr->capacity - old_capacity) * sizeof(void*));
2828
}
2929

3030
void add_element(Array *arr, void *element) {

src/vabackend.c

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -240,29 +240,29 @@ static void freeBuffer(AppendableBuffer *ab) {
240240
}
241241
}
242242

243-
static Object allocateObject(NVDriver *drv, ObjectType type, int allocatePtrSize) {
243+
static Object allocateObject(NVDriver *drv, ObjectType type, size_t allocatePtrSize) {
244244
Object newObj = (Object) calloc(1, sizeof(struct Object_t));
245245

246246
newObj->type = type;
247-
newObj->id = (++drv->nextObjId);
248247

249248
if (allocatePtrSize > 0) {
250249
newObj->obj = calloc(1, allocatePtrSize);
251250
}
252251

253252
pthread_mutex_lock(&drv->objectCreationMutex);
253+
newObj->id = (++drv->nextObjId);
254254
add_element(&drv->objects, newObj);
255255
pthread_mutex_unlock(&drv->objectCreationMutex);
256256

257257
return newObj;
258258
}
259259

260-
static Object getObject(NVDriver *drv, VAGenericID id) {
260+
static Object getObject(NVDriver *drv, ObjectType type, VAGenericID id) {
261261
Object ret = NULL;
262262
if (id != VA_INVALID_ID) {
263263
pthread_mutex_lock(&drv->objectCreationMutex);
264264
ARRAY_FOR_EACH(Object, o, &drv->objects)
265-
if (o->id == id) {
265+
if (o->id == id && o->type == type) {
266266
ret = o;
267267
break;
268268
}
@@ -272,22 +272,22 @@ static Object getObject(NVDriver *drv, VAGenericID id) {
272272
return ret;
273273
}
274274

275-
static void* getObjectPtr(NVDriver *drv, VAGenericID id) {
275+
static void* getObjectPtr(NVDriver *drv, ObjectType type, VAGenericID id) {
276276
if (id != VA_INVALID_ID) {
277-
Object o = getObject(drv, id);
277+
Object o = getObject(drv, type, id);
278278
if (o != NULL) {
279279
return o->obj;
280280
}
281281
}
282282
return NULL;
283283
}
284284

285-
static Object getObjectByPtr(NVDriver *drv, void *ptr) {
285+
static Object getObjectByPtr(NVDriver *drv, ObjectType type, void *ptr) {
286286
Object ret = NULL;
287287
if (ptr != NULL) {
288288
pthread_mutex_lock(&drv->objectCreationMutex);
289289
ARRAY_FOR_EACH(Object, o, &drv->objects)
290-
if (o->obj == ptr) {
290+
if (o->obj == ptr && o->type == type) {
291291
ret = o;
292292
break;
293293
}
@@ -351,15 +351,15 @@ static void deleteAllObjects(NVDriver *drv) {
351351
LOG("Found object %d or type %d", o->id, o->type);
352352
if (o->type == OBJECT_TYPE_CONTEXT) {
353353
destroyContext(drv, (NVContext*) o->obj);
354-
deleteObject(drv, o->id);
355354
}
355+
deleteObject(drv, o->id);
356356
END_FOR_EACH
357357
pthread_mutex_unlock(&drv->objectCreationMutex);
358358
}
359359

360360
NVSurface* nvSurfaceFromSurfaceId(NVDriver *drv, VASurfaceID surf) {
361-
Object obj = getObject(drv, surf);
362-
if (obj != NULL && obj->type == OBJECT_TYPE_SURFACE) {
361+
Object obj = getObject(drv, OBJECT_TYPE_SURFACE, surf);
362+
if (obj != NULL) {
363363
NVSurface *suf = (NVSurface*) obj->obj;
364364
return suf;
365365
}
@@ -428,14 +428,6 @@ static void* resolveSurfaces(void *param) {
428428
ctx->surfaceQueueReadIdx = 0;
429429
}
430430

431-
if (surface->decodeFailed) {
432-
pthread_mutex_lock(&surface->mutex);
433-
surface->resolving = 0;
434-
pthread_cond_signal(&surface->cond);
435-
pthread_mutex_unlock(&surface->mutex);
436-
continue;
437-
}
438-
439431
CUdeviceptr deviceMemory = (CUdeviceptr) NULL;
440432
unsigned int pitch = 0;
441433

@@ -447,7 +439,7 @@ static void* resolveSurfaces(void *param) {
447439
};
448440

449441
//LOG("Mapping surface %d", surface->pictureIdx);
450-
if (CHECK_CUDA_RESULT(cv->cuvidMapVideoFrame(ctx->decoder, surface->pictureIdx, &deviceMemory, &pitch, &procParams))) {
442+
if (surface->decodeFailed || CHECK_CUDA_RESULT(cv->cuvidMapVideoFrame(ctx->decoder, surface->pictureIdx, &deviceMemory, &pitch, &procParams))) {
451443
pthread_mutex_lock(&surface->mutex);
452444
surface->resolving = 0;
453445
pthread_cond_signal(&surface->cond);
@@ -841,7 +833,7 @@ static VAStatus nvQueryConfigAttributes(
841833
)
842834
{
843835
NVDriver *drv = (NVDriver*) ctx->pDriverData;
844-
NVConfig *cfg = (NVConfig*) getObjectPtr(drv, config_id);
836+
NVConfig *cfg = (NVConfig*) getObjectPtr(drv, OBJECT_TYPE_CONFIG, config_id);
845837

846838
if (cfg == NULL) {
847839
return VA_STATUS_ERROR_INVALID_CONFIG;
@@ -976,11 +968,9 @@ static VAStatus nvCreateSurfaces2(
976968
pthread_mutex_init(&suf->mutex, NULL);
977969
pthread_cond_init(&suf->cond, NULL);
978970

979-
LOG("Creating surface %dx%d, format %X (%p)", width, height, format, suf);
971+
LOG("Creating surface %ux%u, format %X (%p)", width, height, format, suf);
980972
}
981973

982-
drv->surfaceCount += num_surfaces;
983-
984974
CHECK_CUDA_RESULT_RETURN(cu->cuCtxPopCurrent(NULL), VA_STATUS_ERROR_OPERATION_FAILED);
985975

986976
return VA_STATUS_SUCCESS;
@@ -1008,7 +998,10 @@ static VAStatus nvDestroySurfaces(
1008998
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1009999

10101000
for (int i = 0; i < num_surfaces; i++) {
1011-
NVSurface *surface = (NVSurface*) getObjectPtr(drv, surface_list[i]);
1001+
NVSurface *surface = (NVSurface*) getObjectPtr(drv, OBJECT_TYPE_SURFACE, surface_list[i]);
1002+
if (!surface) {
1003+
return VA_STATUS_ERROR_INVALID_SURFACE;
1004+
}
10121005

10131006
LOG("Destroying surface %d (%p)", surface->pictureIdx, surface);
10141007

@@ -1017,8 +1010,6 @@ static VAStatus nvDestroySurfaces(
10171010
deleteObject(drv, surface_list[i]);
10181011
}
10191012

1020-
drv->surfaceCount = MAX(drv->surfaceCount - num_surfaces, 0);
1021-
10221013
return VA_STATUS_SUCCESS;
10231014
}
10241015

@@ -1034,13 +1025,13 @@ static VAStatus nvCreateContext(
10341025
)
10351026
{
10361027
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1037-
NVConfig *cfg = (NVConfig*) getObjectPtr(drv, config_id);
1028+
NVConfig *cfg = (NVConfig*) getObjectPtr(drv, OBJECT_TYPE_CONFIG, config_id);
10381029

10391030
if (cfg == NULL) {
10401031
return VA_STATUS_ERROR_INVALID_CONFIG;
10411032
}
10421033

1043-
LOG("creating context with %d render targets, %d surfaces, at %dx%d", num_render_targets, drv->surfaceCount, picture_width, picture_height);
1034+
LOG("creating context with %d render targets, at %dx%d", num_render_targets, picture_width, picture_height);
10441035

10451036
//find the codec they've selected
10461037
const NVCodec *selectedCodec = NULL;
@@ -1059,7 +1050,7 @@ static VAStatus nvCreateContext(
10591050

10601051
if (num_render_targets) {
10611052
// Update the decoder configuration to match the passed in surfaces.
1062-
NVSurface *surface = (NVSurface *) getObjectPtr(drv, render_targets[0]);
1053+
NVSurface *surface = (NVSurface *) getObjectPtr(drv, OBJECT_TYPE_SURFACE, render_targets[0]);
10631054
if (!surface) {
10641055
return VA_STATUS_ERROR_INVALID_PARAMETER;
10651056
}
@@ -1114,10 +1105,6 @@ static VAStatus nvCreateContext(
11141105
.ulNumDecodeSurfaces = surfaceCount,
11151106
};
11161107

1117-
//reset this to 0 as there are some cases where the context will be destroyed but not terminated, meaning if it's initialised again
1118-
//we'll have even more surfaces
1119-
drv->surfaceCount = 0;
1120-
11211108
CHECK_CUDA_RESULT_RETURN(cv->cuvidCtxLockCreate(&vdci.vidLock, drv->cudaContext), VA_STATUS_ERROR_OPERATION_FAILED);
11221109

11231110
CUvideodecoder decoder;
@@ -1160,7 +1147,7 @@ static VAStatus nvDestroyContext(
11601147
NVDriver *drv = (NVDriver*) ctx->pDriverData;
11611148
LOG("Destroying context: %d", context);
11621149

1163-
NVContext *nvCtx = (NVContext*) getObjectPtr(drv, context);
1150+
NVContext *nvCtx = (NVContext*) getObjectPtr(drv, OBJECT_TYPE_CONTEXT, context);
11641151

11651152
if (nvCtx == NULL) {
11661153
return VA_STATUS_ERROR_INVALID_CONTEXT;
@@ -1190,19 +1177,19 @@ static VAStatus nvCreateBuffer(
11901177
//LOG("got buffer %p, type %x, size %u, elements %u", data, type, size, num_elements);
11911178
NVDriver *drv = (NVDriver*) ctx->pDriverData;
11921179

1193-
NVContext *nvCtx = (NVContext*) getObjectPtr(drv, context);
1180+
NVContext *nvCtx = (NVContext*) getObjectPtr(drv, OBJECT_TYPE_CONTEXT, context);
11941181
if (nvCtx == NULL) {
11951182
return VA_STATUS_ERROR_INVALID_CONTEXT;
11961183
}
11971184

11981185
//HACK: This is an awful hack to support VP8 videos when running within FFMPEG.
11991186
//VA-API doesn't pass enough information for NVDEC to work with, but the information is there
12001187
//just before the start of the buffer that was passed to us.
1201-
int offset = 0;
1188+
size_t offset = 0;
12021189
if (nvCtx->profile == VAProfileVP8Version0_3 && type == VASliceDataBufferType) {
1203-
offset = (int) (((uintptr_t) data) & 0xf);
1190+
offset = ((uintptr_t) data) & 0xf;
12041191
data = ((char *) data) - offset;
1205-
size += offset;
1192+
size += (unsigned int)offset;
12061193
}
12071194

12081195
//TODO should pool these as most of the time these should be the same size
@@ -1217,7 +1204,7 @@ static VAStatus nvCreateBuffer(
12171204
buf->offset = offset;
12181205

12191206
if (buf->ptr == NULL) {
1220-
LOG("Unable to allocate buffer of %d bytes", buf->size);
1207+
LOG("Unable to allocate buffer of %lu bytes", buf->size);
12211208
return VA_STATUS_ERROR_ALLOCATION_FAILED;
12221209
}
12231210

@@ -1245,7 +1232,7 @@ static VAStatus nvMapBuffer(
12451232
)
12461233
{
12471234
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1248-
NVBuffer *buf = getObjectPtr(drv, buf_id);
1235+
NVBuffer *buf = getObjectPtr(drv, OBJECT_TYPE_BUFFER, buf_id);
12491236

12501237
if (buf == NULL) {
12511238
return VA_STATUS_ERROR_INVALID_BUFFER;
@@ -1270,7 +1257,7 @@ static VAStatus nvDestroyBuffer(
12701257
)
12711258
{
12721259
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1273-
NVBuffer *buf = getObjectPtr(drv, buffer_id);
1260+
NVBuffer *buf = getObjectPtr(drv, OBJECT_TYPE_BUFFER, buffer_id);
12741261

12751262
if (buf == NULL) {
12761263
return VA_STATUS_ERROR_INVALID_BUFFER;
@@ -1292,8 +1279,12 @@ static VAStatus nvBeginPicture(
12921279
)
12931280
{
12941281
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1295-
NVContext *nvCtx = (NVContext*) getObjectPtr(drv, context);
1296-
NVSurface *surface = (NVSurface*) getObjectPtr(drv, render_target);
1282+
NVContext *nvCtx = (NVContext*) getObjectPtr(drv, OBJECT_TYPE_CONTEXT, context);
1283+
NVSurface *surface = (NVSurface*) getObjectPtr(drv, OBJECT_TYPE_SURFACE, render_target);
1284+
1285+
if (nvCtx == NULL) {
1286+
return VA_STATUS_ERROR_INVALID_CONTEXT;
1287+
}
12971288

12981289
if (surface == NULL) {
12991290
return VA_STATUS_ERROR_INVALID_SURFACE;
@@ -1338,7 +1329,7 @@ static VAStatus nvRenderPicture(
13381329
)
13391330
{
13401331
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1341-
NVContext *nvCtx = (NVContext*) getObjectPtr(drv, context);
1332+
NVContext *nvCtx = (NVContext*) getObjectPtr(drv, OBJECT_TYPE_CONTEXT, context);
13421333

13431334
if (nvCtx == NULL) {
13441335
return VA_STATUS_ERROR_INVALID_CONTEXT;
@@ -1347,7 +1338,7 @@ static VAStatus nvRenderPicture(
13471338
CUVIDPICPARAMS *picParams = &nvCtx->pPicParams;
13481339

13491340
for (int i = 0; i < num_buffers; i++) {
1350-
NVBuffer *buf = (NVBuffer*) getObject(drv, buffers[i])->obj;
1341+
NVBuffer *buf = (NVBuffer*) getObjectPtr(drv, OBJECT_TYPE_BUFFER, buffers[i]);
13511342
if (buf == NULL || buf->ptr == NULL) {
13521343
LOG("Invalid buffer detected, skipping: %d", buffers[i]);
13531344
continue;
@@ -1369,7 +1360,7 @@ static VAStatus nvEndPicture(
13691360
)
13701361
{
13711362
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1372-
NVContext *nvCtx = (NVContext*) getObject(drv, context)->obj;
1363+
NVContext *nvCtx = (NVContext*) getObjectPtr(drv, OBJECT_TYPE_CONTEXT, context);
13731364

13741365
if (nvCtx == NULL) {
13751366
return VA_STATUS_ERROR_INVALID_CONTEXT;
@@ -1422,7 +1413,7 @@ static VAStatus nvSyncSurface(
14221413
)
14231414
{
14241415
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1425-
NVSurface *surface = getObjectPtr(drv, render_target);
1416+
NVSurface *surface = getObjectPtr(drv, OBJECT_TYPE_SURFACE, render_target);
14261417

14271418
if (surface == NULL) {
14281419
return VA_STATUS_ERROR_INVALID_SURFACE;
@@ -1597,13 +1588,14 @@ static VAStatus nvDestroyImage(
15971588
)
15981589
{
15991590
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1600-
NVImage *img = (NVImage*) getObjectPtr(drv, image);
1591+
NVImage *img = (NVImage*) getObjectPtr(drv, OBJECT_TYPE_IMAGE, image);
16011592

16021593
if (img == NULL) {
16031594
return VA_STATUS_ERROR_INVALID_IMAGE;
16041595
}
16051596

1606-
Object imageBufferObj = getObjectByPtr(drv, img->imageBuffer);
1597+
Object imageBufferObj = getObjectByPtr(drv, OBJECT_TYPE_BUFFER, img->imageBuffer);
1598+
16071599
if (imageBufferObj != NULL) {
16081600
if (img->imageBuffer->ptr != NULL) {
16091601
free(img->imageBuffer->ptr);
@@ -1644,8 +1636,17 @@ static VAStatus nvGetImage(
16441636
{
16451637
NVDriver *drv = (NVDriver*) ctx->pDriverData;
16461638

1647-
NVSurface *surfaceObj = (NVSurface*) getObject(drv, surface)->obj;
1648-
NVImage *imageObj = (NVImage*) getObject(drv, image)->obj;
1639+
NVSurface *surfaceObj = (NVSurface*) getObjectPtr(drv, OBJECT_TYPE_SURFACE, surface);
1640+
NVImage *imageObj = (NVImage*) getObjectPtr(drv, OBJECT_TYPE_IMAGE, image);
1641+
1642+
if (surfaceObj == NULL) {
1643+
return VA_STATUS_ERROR_INVALID_SURFACE;
1644+
}
1645+
1646+
if (imageObj == NULL) {
1647+
return VA_STATUS_ERROR_INVALID_IMAGE;
1648+
}
1649+
16491650
NVContext *context = (NVContext*) surfaceObj->context;
16501651
const NVFormatInfo *fmtInfo = &formatsInfo[imageObj->format];
16511652
uint32_t offset = 0;
@@ -1842,7 +1843,7 @@ static VAStatus nvQuerySurfaceAttributes(
18421843
)
18431844
{
18441845
NVDriver *drv = (NVDriver*) ctx->pDriverData;
1845-
NVConfig *cfg = (NVConfig*) getObjectPtr(drv, config);
1846+
NVConfig *cfg = (NVConfig*) getObjectPtr(drv, OBJECT_TYPE_CONFIG, config);
18461847

18471848
if (cfg == NULL) {
18481849
return VA_STATUS_ERROR_INVALID_CONFIG;
@@ -2113,7 +2114,7 @@ static VAStatus nvExportSurfaceHandle(
21132114
return VA_STATUS_ERROR_INVALID_SURFACE;
21142115
}
21152116

2116-
NVSurface *surface = (NVSurface*) getObjectPtr(drv, surface_id);
2117+
NVSurface *surface = (NVSurface*) getObjectPtr(drv, OBJECT_TYPE_SURFACE, surface_id);
21172118
if (surface == NULL) {
21182119
return VA_STATUS_ERROR_INVALID_SURFACE;
21192120
}

0 commit comments

Comments
 (0)