sl@0: // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\heap\t_heapdb.cpp sl@0: // Tests the _DEBUG build dependent aspects of RHeap sl@0: // Overview: sl@0: // Tests debug build dependent aspects of RHeap. sl@0: // API Information: sl@0: // RHeap. sl@0: // Details: sl@0: // Test1: sl@0: // - Allocate a variety of user heap objects and verify the nesting level, allocation count, sl@0: // allocation level and length are correct. Also check for heap corruption. sl@0: // Test 2: sl@0: // - Some assorted indirect calls to alloc, and verify the nesting level, allocation count, sl@0: // allocation level and length are correct. Also check for heap corruption. sl@0: // Test3: sl@0: // - Allocate a variety of objects and verify that the UHEAP_CHECKALL count is correct. sl@0: // - Verify the nesting of UHEAP_MARK and UHEAP_MARKEND macros. sl@0: // - Check the validity of the current thread's default heap. sl@0: // Test4: sl@0: // - Allocate memory for different heaps, check the total number of allocated cells sl@0: // for different heaps and for the current nested level is as expected. sl@0: // Test5: sl@0: // - Simulate heap allocation failures, allocate the memory from user and sl@0: // kernel heap and check results are as expected. sl@0: // Platforms/Drives/Compatibility: sl@0: // All sl@0: // Assumptions/Requirement/Pre-requisites: sl@0: // Failures and causes: sl@0: // Base Port information: sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: LOCAL_D RTest test(_L("T_HEAPDB")); sl@0: sl@0: #if defined(_DEBUG) sl@0: sl@0: RHeap::SHeapCellInfo CellInfo[4]; sl@0: sl@0: class RTestHeap : public RHeap sl@0: { sl@0: public: sl@0: void AttachInfo(SHeapCellInfo* aInfo) sl@0: {iTestData = aInfo;} sl@0: }; sl@0: sl@0: void AttachToHeap(RHeap* aHeap, TInt aInfo) sl@0: { sl@0: if (!aHeap) sl@0: aHeap = (RHeap*)&User::Allocator(); sl@0: ((RTestHeap*)aHeap)->AttachInfo(CellInfo + aInfo); sl@0: } sl@0: sl@0: void TestCellInfo(TInt aInfo, TInt aNest, TInt aAllocCount, TInt aLevelAlloc, TInt aSize, TAny* aAddr) sl@0: { sl@0: RHeap::SHeapCellInfo& ci = CellInfo[aInfo]; sl@0: RHeap::SDebugCell& cell = *ci.iStranded; sl@0: test(cell.nestingLevel == aNest); sl@0: test(cell.allocCount == aAllocCount); sl@0: test(ci.iLevelAlloc == aLevelAlloc); sl@0: test(cell.len == aSize + RHeap::EAllocCellSize); sl@0: test((&cell+1) == aAddr); sl@0: } sl@0: sl@0: const TInt KMaxFailureRate=100; sl@0: const TInt KThreadMemError=-50; sl@0: const TInt KCellSize=(sizeof(RHeap::SCell)); // Size of free cell header sl@0: const TInt KHeadSize=(sizeof(RHeap::SDebugCell)); // Size of allocated cell header with space for heaven info sl@0: sl@0: LOCAL_D TInt heapCount=1; sl@0: LOCAL_D RSemaphore threadSemaphore; sl@0: LOCAL_D TBool array1[KMaxFailureRate+1]; sl@0: LOCAL_D TBool array2[KMaxFailureRate+1]; sl@0: sl@0: LOCAL_C TInt ThreadEntryPoint(TAny*) sl@0: { sl@0: threadSemaphore.Wait(); sl@0: if (User::Alloc(4)==NULL) sl@0: return(KThreadMemError); sl@0: else sl@0: return(KErrNone); sl@0: } sl@0: sl@0: class TestRHeapDebug sl@0: { sl@0: public: sl@0: void Test1(void); sl@0: void Test2(void); sl@0: void Test3(void); sl@0: void Test4(void); sl@0: void Test5(void); sl@0: }; sl@0: sl@0: LOCAL_C RHeap* allocHeap(TInt aSize) sl@0: // sl@0: // Allocate a chunk heap with max size aSize sl@0: // sl@0: { sl@0: sl@0: TName n; sl@0: n.Format(_L("TESTHEAP%d"),heapCount++); sl@0: return(User::ChunkHeap(&n,aSize,aSize)); sl@0: } sl@0: sl@0: void TestRHeapDebug::Test1(void) sl@0: { sl@0: sl@0: TAny* p; sl@0: sl@0: /////////////////////// sl@0: // Test heaven cell is found for each method of allocating memory sl@0: //////////////////////// sl@0: sl@0: // new(TInt aSize) sl@0: __UHEAP_MARK; sl@0: __UHEAP_CHECKALL(0); sl@0: __UHEAP_CHECK(0); sl@0: p=new TUint; sl@0: __UHEAP_CHECKALL(1); sl@0: __UHEAP_CHECK(1); sl@0: __UHEAP_MARKEND; sl@0: __UHEAP_CHECK(0); sl@0: __UHEAP_CHECKALL(1); sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: sl@0: // new(TInt aSize,TInt anExtraSize) sl@0: __UHEAP_MARK; sl@0: p=new(4) TUint; sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: sl@0: // new(TInt aSize,TLeave) sl@0: __UHEAP_MARK; sl@0: p=new(ELeave) TUint; sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: sl@0: // Alloc sl@0: __UHEAP_MARK; sl@0: p=User::Alloc(32); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: sl@0: // AllocL sl@0: __UHEAP_MARK; sl@0: p=User::AllocL(32); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: sl@0: // ReAlloc with Null parameter sl@0: __UHEAP_MARK; sl@0: p=User::ReAlloc(NULL, 32); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: sl@0: // ReAllocL with Null parameter sl@0: __UHEAP_MARK; sl@0: p=User::ReAllocL(NULL, 32); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: sl@0: // ReAlloc with non Null parameter sl@0: __UHEAP_MARK; sl@0: p=User::Alloc(128); sl@0: p=User::ReAlloc(p, 4); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: sl@0: // ReAlloc with non Null parameter such that cell is moved in memory sl@0: __UHEAP_MARK; sl@0: p=User::Alloc(128); sl@0: TAny* temp=User::Alloc(128); sl@0: p=User::ReAlloc(p, 526); sl@0: User::Free(temp); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 3, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: sl@0: // ReAllocL with non Null parameter sl@0: __UHEAP_MARK; sl@0: p=User::Alloc(32); sl@0: p=User::ReAllocL(p, 128); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p), p); sl@0: User::Free(p); sl@0: } sl@0: sl@0: sl@0: void TestRHeapDebug::Test2(void) sl@0: { sl@0: // Some assorted indirect calls to alloc sl@0: sl@0: __UHEAP_MARK; sl@0: CBufFlat* pBuf=CBufFlat::NewL(10); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(pBuf), pBuf); sl@0: delete pBuf; sl@0: sl@0: __UHEAP_MARK; sl@0: HBufC8* pHBufC=HBufC8::New(10); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(pHBufC), pHBufC); sl@0: delete pHBufC; sl@0: sl@0: // can also create a HBufC8 from a descriptor by using TDesC::Alloc sl@0: } sl@0: sl@0: sl@0: void TestRHeapDebug::Test3(void) sl@0: { sl@0: sl@0: // Check num of cells detected is correct and CHECKTOTALNUM is ok sl@0: // NOTE: CHECKTOTALNUM counts the TOTAL number of allocations in the heap regardless of sl@0: // any MARKSTARTs sl@0: // NOTE: the alloc count commences from the FIRST occurrence of a MARKSTART, so if one is nested sl@0: // in another the alloc count will only start from the second MARKSTART if it applies to a sl@0: // different heap. sl@0: __UHEAP_MARK; sl@0: __UHEAP_CHECKALL(0); sl@0: TAny* p1= new TUint; sl@0: __UHEAP_CHECKALL(1); sl@0: TAny* p2= new(20) TUint; sl@0: __UHEAP_CHECKALL(2); sl@0: TAny* p3= User::Alloc(15); sl@0: __UHEAP_CHECKALL(3); sl@0: __UHEAP_MARK; sl@0: __UHEAP_CHECK(0); sl@0: TAny* p4=User::Alloc(1); sl@0: TAny* p5 =new TUint; sl@0: __UHEAP_CHECK(2); sl@0: __UHEAP_CHECKALL(5); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 2, 4, 2, User::AllocLen(p4), p4); sl@0: __UHEAP_CHECKALL(5); sl@0: __UHEAP_CHECK(3); sl@0: __UHEAP_MARKENDC(3); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: User::Free(p3); sl@0: User::Free(p4); sl@0: User::Free(p5); sl@0: sl@0: // Check some nesting out sl@0: p1=new TUint; sl@0: __UHEAP_MARK; sl@0: p2=new TUint; sl@0: __UHEAP_MARK; sl@0: p3=new TUint; sl@0: __UHEAP_MARK; sl@0: p4=new TUint; sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 3, 3, 1, User::AllocLen(p4), p4); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 2, 2, 1, User::AllocLen(p3), p3); sl@0: __UHEAP_MARKEND; sl@0: TestCellInfo(0, 1, 1, 1, User::AllocLen(p2), p2); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: User::Free(p3); sl@0: User::Free(p4); sl@0: User::Check(); sl@0: } sl@0: sl@0: void TestRHeapDebug::Test4(void) sl@0: { sl@0: // Test with different heaps sl@0: TAny* p1=new TUint; sl@0: __UHEAP_MARK; // Default start sl@0: __UHEAP_CHECKALL(1); sl@0: __UHEAP_CHECK(0); sl@0: TAny* p2=new TUint; sl@0: RHeap* pHeap1=allocHeap(1000); sl@0: AttachToHeap(pHeap1,1); sl@0: __RHEAP_MARK(pHeap1); // Heap1 start sl@0: __RHEAP_CHECKALL(pHeap1,0); sl@0: __RHEAP_CHECK(pHeap1,0); sl@0: TAny* p3=pHeap1->Alloc(4); sl@0: __RHEAP_CHECKALL(pHeap1,1); sl@0: __RHEAP_CHECK(pHeap1,1); sl@0: __RHEAP_CHECKALL(pHeap1,1); sl@0: __UHEAP_CHECKALL(3); sl@0: RHeap* pHeap2=allocHeap(1000); sl@0: AttachToHeap(pHeap2,2); sl@0: RHeap* pHeap3=allocHeap(1000); sl@0: AttachToHeap(pHeap3,3); sl@0: __UHEAP_CHECKALL(5); sl@0: __RHEAP_MARK(pHeap2); // Heap2 start sl@0: __RHEAP_MARK(pHeap3); // Heap3 start sl@0: TAny* p4=pHeap2->Alloc(8); sl@0: TAny* p5=pHeap2->Alloc(37); sl@0: TAny* p6=pHeap3->Alloc(32); sl@0: TAny* p7=pHeap1->Alloc(43); sl@0: __UHEAP_CHECKALL(5); sl@0: __RHEAP_CHECKALL(pHeap1,2); sl@0: __RHEAP_CHECKALL(pHeap2,2); sl@0: __RHEAP_CHECKALL(pHeap3,1); sl@0: __RHEAP_MARKEND(pHeap3); // Heap3 end sl@0: TestCellInfo(3, 1, 1, 1, pHeap3->AllocLen(p6), p6); sl@0: __RHEAP_MARKEND(pHeap2); // Heap2 end sl@0: TestCellInfo(2, 1, 1, 2, pHeap2->AllocLen(p4), p4); sl@0: pHeap1->Free(p3); sl@0: __RHEAP_MARKEND(pHeap1); // Heap1 end sl@0: TestCellInfo(1, 1, 2, 1, pHeap1->AllocLen(p7), p7); sl@0: User::Free(p1); sl@0: User::Free(p2); sl@0: pHeap2->Free(p4); sl@0: pHeap2->Free(p5); sl@0: pHeap3->Free(p6); sl@0: pHeap1->Free(p7); sl@0: __UHEAP_CHECKALL(3); sl@0: pHeap2->Close(); sl@0: pHeap3->Close(); sl@0: __UHEAP_MARKEND; sl@0: pHeap1->Close(); sl@0: __UHEAP_CHECKALL(0); sl@0: } sl@0: sl@0: void TestRHeapDebug::Test5() sl@0: // Check the alloc failure macros sl@0: { sl@0: TAny *p, *p1; sl@0: RHeap* pHeap=allocHeap(1000); sl@0: sl@0: // DETERMINISTIC FAILURE sl@0: __UHEAP_RESET; sl@0: __UHEAP_FAILNEXT(1); sl@0: test(User::Alloc(1)==NULL); sl@0: p=User::Alloc(1); sl@0: test(p!=NULL); sl@0: User::FreeZ(p); sl@0: __UHEAP_RESET; sl@0: sl@0: __RHEAP_RESET(pHeap); sl@0: __RHEAP_FAILNEXT(pHeap,1); sl@0: test(pHeap->Alloc(1)==NULL); sl@0: p=pHeap->Alloc(1); sl@0: test(p!=NULL); sl@0: pHeap->FreeZ(p); sl@0: __RHEAP_RESET(pHeap); sl@0: sl@0: __KHEAP_RESET; sl@0: __KHEAP_FAILNEXT(1); sl@0: RSemaphore semaphore; sl@0: test(semaphore.CreateLocal(1)==KErrNoMemory); // allocated from the kernel heap sl@0: test(semaphore.CreateLocal(1)==KErrNone); sl@0: semaphore.Close(); sl@0: __KHEAP_RESET; sl@0: sl@0: __UHEAP_SETFAIL(RHeap::EDeterministic,0); sl@0: test(User::Alloc(1)==NULL); sl@0: __UHEAP_RESET; sl@0: sl@0: __RHEAP_SETFAIL(pHeap,RHeap::EDeterministic,0); sl@0: test(pHeap->Alloc(1)==NULL); sl@0: __RHEAP_RESET(pHeap); sl@0: sl@0: __KHEAP_SETFAIL(RHeap::EDeterministic,0); sl@0: test(semaphore.CreateLocal(1)==KErrNoMemory); sl@0: __KHEAP_RESET; sl@0: sl@0: TInt determinism; sl@0: for(determinism=1; determinism<=KMaxFailureRate; determinism++) sl@0: { sl@0: __UHEAP_SETFAIL(RHeap::EDeterministic,determinism); sl@0: __RHEAP_SETFAIL(pHeap,RHeap::EDeterministic,determinism); sl@0: for(TInt ii=1; ii<=determinism; ii++) sl@0: { sl@0: p=User::Alloc(1); sl@0: p1=pHeap->Alloc(1); sl@0: if(ii%determinism==0) sl@0: { sl@0: test(p==NULL); sl@0: test(p1==NULL); sl@0: } sl@0: else sl@0: { sl@0: test(p!=NULL); sl@0: test(p1!=NULL); sl@0: pHeap->Free(p1); sl@0: User::Free(p); sl@0: } sl@0: } sl@0: } sl@0: __UHEAP_RESET; sl@0: __RHEAP_RESET(pHeap); sl@0: sl@0: // Test SetKernelAllocFail sl@0: // its not possible to test SetKernelAllocFail as above as it is not possible to control the sl@0: // number of calls to Alloc for the dernel heap - but the following will definitely fail: sl@0: __KHEAP_SETFAIL(RHeap::EDeterministic,1); sl@0: RSemaphore r; sl@0: test(r.CreateLocal(1)==KErrNoMemory); // allocated from the kernel heap sl@0: __KHEAP_SETFAIL(RHeap::EDeterministic,50); sl@0: test(r.CreateLocal(1)==KErrNone); sl@0: r.Close(); sl@0: __KHEAP_RESET; sl@0: sl@0: // RANDOM TESTS sl@0: TInt numOccurences1, numOccurences2; sl@0: sl@0: __UHEAP_SETFAIL(RHeap::ERandom,1); sl@0: test(User::Alloc(1)==NULL); sl@0: __UHEAP_RESET; sl@0: sl@0: __RHEAP_SETFAIL(pHeap,RHeap::ERandom,1); sl@0: test(pHeap->Alloc(1)==NULL); sl@0: __RHEAP_RESET(pHeap); sl@0: sl@0: // __KHEAP_SETFAIL(RHeap::ERandom,1); sl@0: // test(semaphore.CreateLocal(1)==KErrNoMemory); sl@0: // __KHEAP_RESET; sl@0: sl@0: __UHEAP_SETFAIL(RHeap::ETrueRandom,1); sl@0: test(User::Alloc(1)==NULL); sl@0: __UHEAP_RESET; sl@0: sl@0: __RHEAP_SETFAIL(pHeap,RHeap::ETrueRandom,1); sl@0: test(pHeap->Alloc(1)==NULL); sl@0: __RHEAP_RESET(pHeap); sl@0: sl@0: // __KHEAP_SETFAIL(RHeap::ETrueRandom,1); sl@0: // test(semaphore.CreateLocal(1)==KErrNoMemory); sl@0: // __KHEAP_RESET; sl@0: sl@0: for(determinism=1; determinism<=KMaxFailureRate; determinism++) sl@0: { sl@0: __UHEAP_SETFAIL(RHeap::ERandom,determinism); sl@0: __RHEAP_SETFAIL(pHeap,RHeap::ERandom,determinism); sl@0: TInt ii; sl@0: for(ii=1; ii<=determinism; ii++) sl@0: { sl@0: p=User::Alloc(1); sl@0: p1=pHeap->Alloc(1); sl@0: array1[ii]=(p==NULL); sl@0: array2[ii]=(p==NULL); sl@0: if(p) sl@0: User::Free(p); sl@0: if(p1) sl@0: pHeap->Free(p1); sl@0: } sl@0: numOccurences1=0; sl@0: numOccurences2=0; sl@0: for(ii=1; ii<=determinism; ii++) sl@0: { sl@0: if(array1[ii]) sl@0: numOccurences1++; sl@0: if(array2[ii]) sl@0: numOccurences2++; sl@0: } sl@0: test(numOccurences1==1); sl@0: test(numOccurences2==1); sl@0: } sl@0: __UHEAP_RESET; sl@0: __RHEAP_RESET(pHeap); sl@0: sl@0: __UHEAP_SETFAIL(RHeap::ERandom,5); sl@0: TInt ii; sl@0: for(ii=1; ii<=50; ii++) sl@0: { sl@0: p=User::Alloc(1); sl@0: array1[ii]=(p==NULL); sl@0: if(p) sl@0: User::Free(p); sl@0: } sl@0: numOccurences1=0; sl@0: numOccurences2=0; sl@0: for(ii=1; ii<=50; ii++) sl@0: { sl@0: if(array1[ii]) sl@0: { sl@0: numOccurences1++; sl@0: numOccurences2++; sl@0: } sl@0: if(ii%5==0) sl@0: { sl@0: test(numOccurences1==1); sl@0: numOccurences1=0; sl@0: } sl@0: } sl@0: test(numOccurences2==50/5); sl@0: sl@0: // Cannot really test random failure of the kernel heap accurately sl@0: sl@0: pHeap->Close(); sl@0: //client.Disconnect(); sl@0: sl@0: // Test failing the heap of a child thread sl@0: // 1st test that it allocates normally sl@0: TRequestStatus stat; sl@0: RThread thread; sl@0: test(threadSemaphore.CreateLocal(0)==KErrNone); sl@0: test(thread.Create(_L("Thread"),ThreadEntryPoint,KDefaultStackSize,0x200,0x200,NULL)==KErrNone); sl@0: thread.Logon(stat); sl@0: thread.Resume(); sl@0: threadSemaphore.Signal(); sl@0: User::WaitForRequest(stat); sl@0: test(thread.ExitReason()==KErrNone); sl@0: thread.Close(); sl@0: #if defined(CAN_TEST_THREADS) sl@0: // Now make the thread's heap fail sl@0: test(thread.Create(_L("Thread"),ThreadEntryPoint,KDefaultStackSize,0x200,0x200,NULL)==KErrNone); sl@0: thread.Logon(stat); sl@0: thread.Resume(); sl@0: TH_FAILNEXT(thread.Handle()); sl@0: threadSemaphore.Signal(); sl@0: User::WaitForRequest(stat); sl@0: test(thread.ExitReason()==KThreadMemError); sl@0: thread.Close(); sl@0: threadSemaphore.Close(); sl@0: #endif sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main(void) sl@0: { sl@0: sl@0: test.Title(); sl@0: AttachToHeap(NULL,0); sl@0: test.Start(_L("Test1")); sl@0: TestRHeapDebug T; sl@0: T.Test1(); sl@0: test.Next(_L("Test2")); sl@0: T.Test2(); sl@0: test.Next(_L("Test3")); sl@0: T.Test3(); sl@0: test.Next(_L("Test4")); sl@0: T.Test4(); sl@0: test.Next(_L("Test5")); sl@0: T.Test5(); sl@0: test.End(); sl@0: return(0); sl@0: } sl@0: #else sl@0: GLDEF_C TInt E32Main() sl@0: // sl@0: // Test unavailable in release build. sl@0: // sl@0: { sl@0: sl@0: test.Title(); sl@0: test.Start(_L("No tests for release builds")); sl@0: test.End(); sl@0: return(0); sl@0: } sl@0: #endif sl@0: sl@0: sl@0: