fix opencv/opencv#20594 - exception handling with refcounts

This commit is contained in:
Dale Phurrough 2021-08-24 18:56:25 +02:00
parent 9bda96d39e
commit 54a9e00970
No known key found for this signature in database
GPG Key ID: E53384A29713D41F
3 changed files with 66 additions and 28 deletions

View File

@ -749,18 +749,17 @@ Mat::Mat(const Mat& m, const Rect& roi)
data += roi.x*esz; data += roi.x*esz;
CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols &&
0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows ); 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows );
if( u )
CV_XADD(&u->refcount, 1);
if( roi.width < m.cols || roi.height < m.rows ) if( roi.width < m.cols || roi.height < m.rows )
flags |= SUBMATRIX_FLAG; flags |= SUBMATRIX_FLAG;
step[0] = m.step[0]; step[1] = esz; step[0] = m.step[0]; step[1] = esz;
updateContinuityFlag(); updateContinuityFlag();
addref();
if( rows <= 0 || cols <= 0 ) if( rows <= 0 || cols <= 0 )
{ {
release();
rows = cols = 0; rows = cols = 0;
release();
} }
} }

View File

@ -2774,19 +2774,33 @@ struct Kernel::Impl
void cleanupUMats() void cleanupUMats()
{ {
bool exceptionOccurred = false;
for( int i = 0; i < MAX_ARRS; i++ ) for( int i = 0; i < MAX_ARRS; i++ )
{
if( u[i] ) if( u[i] )
{ {
if( CV_XADD(&u[i]->urefcount, -1) == 1 ) if( CV_XADD(&u[i]->urefcount, -1) == 1 )
{ {
u[i]->flags |= UMatData::ASYNC_CLEANUP; u[i]->flags |= UMatData::ASYNC_CLEANUP;
u[i]->currAllocator->deallocate(u[i]); try
{
u[i]->currAllocator->deallocate(u[i]);
}
catch(const std::exception& exc)
{
// limited by legacy before C++11, therefore log and
// remember some exception occurred to throw below
CV_LOG_ERROR(NULL, "OCL: Unexpected C++ exception in OpenCL Kernel::Impl::cleanupUMats(): " << exc.what());
exceptionOccurred = true;
}
} }
u[i] = 0; u[i] = 0;
} }
}
nu = 0; nu = 0;
haveTempDstUMats = false; haveTempDstUMats = false;
haveTempSrcUMats = false; haveTempSrcUMats = false;
CV_Assert(!exceptionOccurred);
} }
void addUMat(const UMat& m, bool dst) void addUMat(const UMat& m, bool dst)
@ -2817,8 +2831,16 @@ struct Kernel::Impl
void finit(cl_event e) void finit(cl_event e)
{ {
CV_UNUSED(e); CV_UNUSED(e);
cleanupUMats();
isInProgress = false; isInProgress = false;
try
{
cleanupUMats();
}
catch(...)
{
release();
throw;
}
release(); release();
} }

View File

@ -540,13 +540,26 @@ UMat Mat::getUMat(int accessFlags, UMatUsageFlags usageFlags) const
CV_XADD(&(u->refcount), 1); CV_XADD(&(u->refcount), 1);
CV_XADD(&(u->urefcount), 1); CV_XADD(&(u->urefcount), 1);
} }
hdr.flags = flags; try
setSize(hdr, dims, size.p, step.p); {
finalizeHdr(hdr); hdr.flags = flags;
hdr.u = new_u; setSize(hdr, dims, size.p, step.p);
hdr.offset = 0; //data - datastart; finalizeHdr(hdr);
hdr.addref(); hdr.u = new_u;
return hdr; hdr.offset = 0; //data - datastart;
hdr.addref();
return hdr;
}
catch(...)
{
if (u != NULL)
{
CV_XADD(&(u->refcount), -1);
CV_XADD(&(u->urefcount), -1);
}
new_u->currAllocator->deallocate(new_u);
throw;
}
} }
void UMat::create(int d, const int* _sizes, int _type, UMatUsageFlags _usageFlags) void UMat::create(int d, const int* _sizes, int _type, UMatUsageFlags _usageFlags)
@ -692,18 +705,17 @@ UMat::UMat(const UMat& m, const Rect& roi)
offset += roi.x*esz; offset += roi.x*esz;
CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols &&
0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows ); 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows );
if( u )
CV_XADD(&(u->urefcount), 1);
if( roi.width < m.cols || roi.height < m.rows ) if( roi.width < m.cols || roi.height < m.rows )
flags |= SUBMATRIX_FLAG; flags |= SUBMATRIX_FLAG;
step[0] = m.step[0]; step[1] = esz; step[0] = m.step[0]; step[1] = esz;
updateContinuityFlag(); updateContinuityFlag();
addref();
if( rows <= 0 || cols <= 0 ) if( rows <= 0 || cols <= 0 )
{ {
release();
rows = cols = 0; rows = cols = 0;
release();
} }
} }
@ -969,24 +981,29 @@ Mat UMat::getMat(int accessFlags) const
// TODO Support ACCESS_READ (ACCESS_WRITE) without unnecessary data transfers // TODO Support ACCESS_READ (ACCESS_WRITE) without unnecessary data transfers
accessFlags |= ACCESS_RW; accessFlags |= ACCESS_RW;
UMatDataAutoLock autolock(u); UMatDataAutoLock autolock(u);
if(CV_XADD(&u->refcount, 1) == 0) try
u->currAllocator->map(u, accessFlags);
if (u->data != 0)
{ {
Mat hdr(dims, size.p, type(), u->data + offset, step.p); if(CV_XADD(&u->refcount, 1) == 0)
hdr.flags = flags; u->currAllocator->map(u, accessFlags);
hdr.u = u; if (u->data != 0)
hdr.datastart = u->data; {
hdr.data = u->data + offset; Mat hdr(dims, size.p, type(), u->data + offset, step.p);
hdr.datalimit = hdr.dataend = u->data + u->size; hdr.flags = flags;
return hdr; hdr.u = u;
hdr.datastart = u->data;
hdr.data = u->data + offset;
hdr.datalimit = hdr.dataend = u->data + u->size;
return hdr;
}
} }
else catch(...)
{ {
CV_XADD(&u->refcount, -1); CV_XADD(&u->refcount, -1);
CV_Assert(u->data != 0 && "Error mapping of UMat to host memory."); throw;
return Mat();
} }
CV_XADD(&u->refcount, -1);
CV_Assert(u->data != 0 && "Error mapping of UMat to host memory.");
return Mat();
} }
void* UMat::handle(int accessFlags) const void* UMat::handle(int accessFlags) const