I’m writing a .dae to .skp importer, using SketchUp’s latest API. I’m also using ASSIMP to read the collada files in.
What I’m noticing is that, on the second iteration of the second inner loop (this happens every time), the call to SUFaceCreate causes a heap corruption exception to be thrown.
What I can say is that I’ve made sure all external libraries used have been compiled with under MSVC 2010 as release builds, in an attempt to make sure there aren’t any debug/release build conflicts going on with allocations and deallocations.
It might be worth noting that the code base I’m working in performs .skp file imports using the deprecated SkpReader API. I’m not sure if this could potentially cause any issues in terms of conflict.
The loop in particular in which the exception is thrown:
for (unsigned face = 0; face < mesh->mNumFaces; ++face)
{
SUFaceRef faceRef = SU_INVALID;
SULoopInputRef indexLoop = SU_INVALID;
SU_CHECK_RESULT( SULoopInputCreate(&indexLoop) );
SU_CHECK_RESULT( SULoopInputAddVertexIndex(indexLoop, mesh->mFaces[face].mIndices[0]) );
SU_CHECK_RESULT( SULoopInputAddVertexIndex(indexLoop, mesh->mFaces[face].mIndices[1]) );
SU_CHECK_RESULT( SULoopInputAddVertexIndex(indexLoop, mesh->mFaces[face].mIndices[2]) );
const aiVector3D& a = mesh->mVertices[mesh->mFaces[face].mIndices[0]];
const aiVector3D& b = mesh->mVertices[mesh->mFaces[face].mIndices[1]];
const aiVector3D& c = mesh->mVertices[mesh->mFaces[face].mIndices[2]];
SUPoint3D triFace[3];
triFace[0].x = a.x;
triFace[0].y = a.y;
triFace[0].z = a.z;
triFace[1].x = b.x;
triFace[1].y = b.y;
triFace[1].z = b.z;
triFace[2].x = c.x;
triFace[2].y = c.y;
triFace[2].z = c.z;
SU_CHECK_RESULT( SUFaceCreate(&faceRef, triFace, &indexLoop) ); // CRASH here, on second iteration.
SU_CHECK_RESULT( SUEntitiesAddFaces(entitiesListRef, 1, &faceRef) );
//faceBuffer.push_back(faceRef); // commented out to ensure deallocation here was not a culprit.
}
Of particular interest in an analysis performed by WinDbg is:
775ad374 774f047b ntdll!RtlAllocateHeap+0xc6
775ad378 69e70269 msvcr100!malloc+0x4b
775ad37c 69e7233b msvcr100!operator new+0x1f
775ad380 6adfd4bf slapi!SUStringSetUTF16+0x1d574f
775ad384 6adfe75c slapi!SUStringSetUTF16+0x1d69ec
775ad388 6adfe7c4 slapi!SUStringSetUTF16+0x1d6a54
775ad38c 6adf1d84 slapi!SUStringSetUTF16+0x1ca014
775ad390 6ac26311 slapi!SUVertexGetLoops+0x421
775ad394 6ac1190e slapi!SUFaceToDrawingElement+0xfe
775ad398 6ac12b43 slapi!SUFaceGetInnerLoops+0x483
775ad39c 6ac1398b slapi!SUFaceCreate+0x7b
775ad3a0 0107df53 myapp!DaeToSkp+0xff3
Full Source File (the marked faulty line is closer to the bottom):
// Will return false within the function on failure
#define SU_CHECK_RESULT(expr) \
do { \
SUResult result = (expr); \
if (result != SU_ERROR_NONE) \
{ \
std::stringstream sstream; \
sstream << "SU IMPORT ERROR: " << ( int )result; \
LOG3(sstream.str().c_str()); \
return false; \
} \
} while(0)
bool DaeToSkp(const char* inFilename, const char* outFilename)
{
Assimp::Importer import;
const aiScene* scene = import.ReadFile(inFilename, 0);
if (!scene)
return false;
aiCamera* daeCamera = scene->mCameras[0];
SUModelRef model = SU_INVALID;
SUEntitiesRef entitiesListRef = SU_INVALID;
SU_CHECK_RESULT( SUModelCreate(&model) );
SU_CHECK_RESULT( SUModelGetEntities(model, &entitiesListRef) );
// Load .dae camera settings into .skp camera
{
SUCameraRef cameraRef = SU_INVALID;
SUPoint3D position = { daeCamera->mPosition.x, daeCamera->mPosition.y, daeCamera->mPosition.z };
SUPoint3D lookAt = { daeCamera->mLookAt.x, daeCamera->mLookAt.y, daeCamera->mLookAt.z };
SUVector3D up = { daeCamera->mUp.x, daeCamera->mUp.y, daeCamera->mUp.z };
SU_CHECK_RESULT( SUModelGetCamera(model, &cameraRef) );
SU_CHECK_RESULT( SUCameraSetPerspective(cameraRef, true) );
SU_CHECK_RESULT( SUCameraSetPerspectiveFrustumFOV(cameraRef, daeCamera->mHorizontalFOV) );
SU_CHECK_RESULT( SUCameraSetOrientation(cameraRef, &position, &lookAt, &up) );
}
//SUGeometryInputRef geomRef = SU_INVALID;
//SU_CHECK_RESULT( SUGeometryInputCreate(&geomRef) );
for (unsigned i = 0; i < scene->mNumMeshes; ++i)
{
aiMesh* mesh = scene->mMeshes[i];
for (unsigned v = 0; v < mesh->mNumVertices; ++v)
{
aiVector3D& point = mesh->mVertices[v];
if (point.Length() > 1.0f)
point.Normalize();
/*
for (unsigned coord = 0; coord < 3; ++coord)
{
if (point[coord] < PLANE_TOLERANCE)
point[coord] = -PLANE_TOLERANCE;
}
*/
}
//std::vector<SUFaceRef> faceBuffer; // commented out to ensure allocation here was not a culprit
for (unsigned face = 0; face < mesh->mNumFaces; ++face)
{
SUFaceRef faceRef = SU_INVALID;
SULoopInputRef indexLoop = SU_INVALID;
SU_CHECK_RESULT( SULoopInputCreate(&indexLoop) );
SU_CHECK_RESULT( SULoopInputAddVertexIndex(indexLoop, mesh->mFaces[face].mIndices[0]) );
SU_CHECK_RESULT( SULoopInputAddVertexIndex(indexLoop, mesh->mFaces[face].mIndices[1]) );
SU_CHECK_RESULT( SULoopInputAddVertexIndex(indexLoop, mesh->mFaces[face].mIndices[2]) );
const aiVector3D& a = mesh->mVertices[mesh->mFaces[face].mIndices[0]];
const aiVector3D& b = mesh->mVertices[mesh->mFaces[face].mIndices[1]];
const aiVector3D& c = mesh->mVertices[mesh->mFaces[face].mIndices[2]];
SUPoint3D triFace[3];
triFace[0].x = a.x;
triFace[0].y = a.y;
triFace[0].z = a.z;
triFace[1].x = b.x;
triFace[1].y = b.y;
triFace[1].z = b.z;
triFace[2].x = c.x;
triFace[2].y = c.y;
triFace[2].z = c.z;
SU_CHECK_RESULT( SUFaceCreate(&faceRef, triFace, &indexLoop) ); // CRASH here, on second iteration.
SU_CHECK_RESULT( SUEntitiesAddFaces(entitiesListRef, 1, &faceRef) );
//faceBuffer.push_back(faceRef); // commented out to ensure deallocation here was not a culprit.
}
LOG1("FACE LOOP SUCCESS");
}
//SUEntitiesFill(entitiesListRef, geomRef, true);
LOG1("SAVING MODEL");
SUModelSaveToFile(model, outFilename);
SUModelRelease(&model);
return true;
}
Full Analysis Report (from WinDbg x86):
0:000> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
*** WARNING: Unable to verify checksum for C:\Dev\myapp\build\bin\x86\Release\slapi.dll
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Dev\myapp\build\bin\x86\Release\slapi.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\SysWOW64\nvd3dum.dll -
FAULTING_IP:
ntdll!RtlReportCriticalFailure+46
7758f5f9 cc int 3
EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 7758f5f9 (ntdll!RtlReportCriticalFailure+0x00000046)
ExceptionCode: 80000003 (Break instruction exception)
ExceptionFlags: 00000000
NumberParameters: 1
Parameter[0]: 00000000
CONTEXT: 00000000 -- (.cxr 0x0;r)
eax=00000000 ebx=00000000 ecx=c0000374 edx=00000021 esi=00000002 edi=0a10cb30
eip=7758f5f9 esp=00c6d958 ebp=00c6d9e8 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00200244
ntdll!RtlReportCriticalFailure+0x46:
7758f5f9 cc int 3
FAULTING_THREAD: 00001040
PROCESS_NAME: myapp.exe
ERROR_CODE: (NTSTATUS) 0x80000003 - {EXCEPTION} Breakpoint A breakpoint has been reached.
EXCEPTION_CODE: (HRESULT) 0x80000003 (2147483651) - One or more arguments are invalid
EXCEPTION_PARAMETER1: 00000000
NTGLOBALFLAG: 0
APPLICATION_VERIFIER_FLAGS: 0
APP: myapp.exe
ANALYSIS_VERSION: 6.3.9600.17237 (debuggers(dbg).140716-0327) x86fre
LAST_CONTROL_TRANSFER: from 77592898 to 7758f5f9
BUGCHECK_STR: APPLICATION_FAULT_ACTIONABLE_HEAP_CORRUPTION_heap_failure_lfh_bitmap_mismatch
PRIMARY_PROBLEM_CLASS: ACTIONABLE_HEAP_CORRUPTION_heap_failure_lfh_bitmap_mismatch
DEFAULT_BUCKET_ID: ACTIONABLE_HEAP_CORRUPTION_heap_failure_lfh_bitmap_mismatch
STACK_TEXT:
775ad370 77526e97 ntdll!RtlpLowFragHeapAllocFromContext+0x3523b
775ad374 774f047b ntdll!RtlAllocateHeap+0xc6
775ad378 69e70269 msvcr100!malloc+0x4b
775ad37c 69e7233b msvcr100!operator new+0x1f
775ad380 6adfd4bf slapi!SUStringSetUTF16+0x1d574f
775ad384 6adfe75c slapi!SUStringSetUTF16+0x1d69ec
775ad388 6adfe7c4 slapi!SUStringSetUTF16+0x1d6a54
775ad38c 6adf1d84 slapi!SUStringSetUTF16+0x1ca014
775ad390 6ac26311 slapi!SUVertexGetLoops+0x421
775ad394 6ac1190e slapi!SUFaceToDrawingElement+0xfe
775ad398 6ac12b43 slapi!SUFaceGetInnerLoops+0x483
775ad39c 6ac1398b slapi!SUFaceCreate+0x7b
775ad3a0 0107df53 myapp!DaeToSkp+0xff3
775ad3a4 0105d3da myapp!BwData::Load+0xa1a
775ad3a8 01086b6e myapp!MainFrame::OpenFile+0x13e
775ad3ac 01086903 myapp!MainFrame::DoImportFile+0x1b3
775ad3b0 01086459 myapp!MainFrame::OnMenu_ImportColladaFile+0x19
775ad3b4 0125a2e0 myapp!wxAppConsoleBase::HandleEvent+0x10
775ad3b8 0125a31d myapp!wxAppConsoleBase::CallEventHandler+0x2d
775ad3bc 01250a7b myapp!wxEvtHandler::SearchDynamicEventTable+0x8b
775ad3c0 0125176f myapp!wxEvtHandler::ProcessEvent+0xef
775ad3c4 0125088b myapp!wxEvtHandler::SafelyProcessEvent+0x3b
775ad3c8 0132e9ef myapp!wxMenuBase::SendEvent+0x7f
775ad3cc 013291f9 myapp!wxFrameBase::ProcessCommand+0x79
775ad3d0 0131cef5 myapp!wxFrame::HandleCommand+0x45
775ad3d4 0131e02a myapp!wxFrame::MSWWindowProc+0x11a
775ad3d8 012f25af myapp!wxWndProc+0x8f
775ad3dc 750b7834 user32!_InternalCallWinProc+0x23
775ad3e0 750b7a9a user32!UserCallWinProcCheckWow+0x184
775ad3e4 750b988e user32!DispatchMessageWorker+0x208
775ad3e8 750d2626 user32!IsDialogMessageW+0x107
775ad3ec 012ef741 myapp!wxWindow::MSWProcessMessage+0x121
FOLLOWUP_IP:
MSVCR100!operator new+1f
69e7233b 59 pop ecx
SYMBOL_STACK_INDEX: 3
SYMBOL_NAME: msvcr100!operator new+1f
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: MSVCR100
IMAGE_NAME: MSVCR100.dll
DEBUG_FLR_IMAGE_TIMESTAMP: 4df2be1e
STACK_COMMAND: dps 775ad370 ; kb
FAILURE_BUCKET_ID: ACTIONABLE_HEAP_CORRUPTION_heap_failure_lfh_bitmap_mismatch_80000003_MSVCR100.dll!operator_new
BUCKET_ID: APPLICATION_FAULT_ACTIONABLE_HEAP_CORRUPTION_heap_failure_lfh_bitmap_mismatch_msvcr100!operator_new+1f
ANALYSIS_SOURCE: UM
FAILURE_ID_HASH_STRING: um:actionable_heap_corruption_heap_failure_lfh_bitmap_mismatch_80000003_msvcr100.dll!operator_new
FAILURE_ID_HASH: {079776fe-d067-8afe-4b4f-bae4c6d17fa9}
Followup: MachineOwner
---------
Conclusion
It looks like allocating an SUFace for the second time is what causes this, given that the error has been thrown on the second iteration literally every-time this has happened. Is there any potential side effects with using the API I should be aware of, or any idea on how to resolve this?
I really appreciate any guidance one could offer in regards to this.