--- /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 <e32test.h>
+#include <e32def.h>
+#include <e32def_private.h>
+
+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
+
+
+