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