kerneltest/e32test/mmu/t_chunk.cpp
changeset 4 56f325a607ea
parent 0 a41df078684a
child 41 0ffb4e86fcc9
--- a/kerneltest/e32test/mmu/t_chunk.cpp	Mon Dec 21 16:14:42 2009 +0000
+++ b/kerneltest/e32test/mmu/t_chunk.cpp	Wed Dec 23 11:43:31 2009 +0000
@@ -37,6 +37,7 @@
 // changes in out of memory status. Verify adjusting an RChunk generates
 // the expected notifications.
 // - Test finding a global chunk by name and verify results are as expected.
+// - Check read-only global chunks cannot be written to by other processes.
 // Platforms/Drives/Compatibility:
 // All.
 // Assumptions/Requirement/Pre-requisites:
@@ -1149,17 +1150,193 @@
 	}
 	
 
-/**Returns true if 'extended' is found in the command line*/
-TBool GetExtended()
+/**Returns true if argument is found in the command line*/
+TBool IsInCommandLine(const TDesC& aArg)
 	{
-	_LIT(KExtended,"extended");
 	TBuf<64> c;
 	User::CommandLine(c);
-	if (c.FindF(KExtended) >= 0)
+	if (c.FindF(aArg) >= 0)
 		return ETrue;
 	return EFalse;
 	}
 
+_LIT(KTestChunkReadOnly, "TestReadOnlyChunk");
+_LIT(KTestSemaphoreReadOnly, "TestReadOnlySemaphore");
+_LIT(KTestParamRo, "restro");
+_LIT(KTestParamRw, "restrw");
+_LIT(KTestParamWait, "restwait");
+_LIT(KTestParamWritableChunk, "restwritable");
+
+enum TTestProcessParameters
+	{
+	ETestRw = 0x1,
+	ETestWait = 0x2,
+	ETestWritableChunk = 0x4,
+	};
+
+void TestReadOnlyProcess(TUint aParams)
+	{
+	TInt r;
+	RChunk chunk;
+	RSemaphore sem;
+
+	test.Start(_L("Open global chunk"));
+	r = chunk.OpenGlobal(KTestChunkReadOnly, EFalse);
+	test_KErrNone(r);
+
+	test(chunk.IsReadable());
+	r = chunk.Adjust(1);
+	if (aParams & ETestWritableChunk)
+		{
+		test(chunk.IsWritable());
+		test_KErrNone(r);
+		}
+	else
+		{
+		test(!chunk.IsWritable());
+		test_Equal(KErrAccessDenied, r);
+		}
+
+	if (aParams & ETestWait)
+		{
+		RProcess::Rendezvous(KErrNone);
+		test.Next(_L("Wait on semaphore"));
+		r = sem.OpenGlobal(KTestSemaphoreReadOnly);
+		test_KErrNone(r);
+		sem.Wait();
+		}
+
+	test.Next(_L("Read"));
+	TUint8 read = *(volatile TUint8*) chunk.Base();
+	(void) read;
+
+	if (aParams & ETestRw)
+		{
+		test.Next(_L("Write"));
+		TUint8* write = chunk.Base();
+		*write = 0x3d;
+		}
+
+	chunk.Close();
+	if (aParams & ETestWait)
+		{
+		sem.Close();
+		}
+	test.End();
+	}
+
+void TestReadOnly()
+	{
+	TInt r;
+	RChunk chunk;
+	RProcess process1;
+	RProcess process2;
+	RSemaphore sem;
+	TRequestStatus rs;
+	TRequestStatus rv;
+
+	// Assumption is made that any memory model from Flexible onwards that supports
+	// read-only memory also supports read-only chunks
+	if (MemModelType() < EMemModelTypeFlexible || !HaveWriteProt())
+		{
+		test.Printf(_L("Memory model is not expected to support Read-Only Chunks\n"));
+		return;
+		}
+
+	TBool jit = User::JustInTime();
+	User::SetJustInTime(EFalse);
+
+	test.Start(_L("Create writable global chunk"));
+	TChunkCreateInfo info;
+	info.SetNormal(0, 1234567);
+	info.SetGlobal(KTestChunkReadOnly);
+	r = chunk.Create(info);
+	test_KErrNone(r);
+	test(chunk.IsReadable());
+	test(chunk.IsWritable());
+
+	test.Next(_L("Adjust size"));
+	r = chunk.Adjust(1); // add one page
+	test_KErrNone(r);
+
+	test.Next(_L("Attempt read/write 1"));
+	r = process1.Create(RProcess().FileName(), KTestParamWritableChunk);
+	test_KErrNone(r);
+	process1.Logon(rs);
+	process1.Resume();
+	User::WaitForRequest(rs);
+	test_Equal(EExitKill, process1.ExitType());
+	test_KErrNone(process1.ExitReason());
+	CLOSE_AND_WAIT(process1);
+	CLOSE_AND_WAIT(chunk);
+
+	test.Next(_L("Create read-only global chunk"));
+	info.SetReadOnly();
+	r = chunk.Create(info);
+	test_KErrNone(r);
+	test(chunk.IsReadable());
+	test(chunk.IsWritable());
+	// To keep in sync with the 'process2' process
+	r = sem.CreateGlobal(KTestSemaphoreReadOnly, 0);
+	test_KErrNone(r);
+
+	test.Next(_L("Attempt read 1"));
+	r = process1.Create(RProcess().FileName(), KTestParamRo);
+	test_KErrNone(r);
+	process1.Logon(rs);
+	process1.Resume();
+	User::WaitForRequest(rs);
+	test_Equal(EExitPanic, process1.ExitType());
+	test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
+	CLOSE_AND_WAIT(process1);
+	// Create second process before commiting memory and make it wait
+	r = process2.Create(RProcess().FileName(), KTestParamWait);
+	test_KErrNone(r)
+	process2.Rendezvous(rv);
+	process2.Resume();
+	User::WaitForRequest(rv);
+
+	test.Next(_L("Adjust size"));
+	r = chunk.Adjust(1); // add one page
+	test_KErrNone(r);
+
+	test.Next(_L("Attempt read 2"));
+	r = process1.Create(RProcess().FileName(), KTestParamRo);
+	test_KErrNone(r);
+	process1.Logon(rs);
+	process1.Resume();
+	User::WaitForRequest(rs);
+	test_Equal(EExitKill, process1.ExitType());
+	test_KErrNone(process1.ExitReason());
+	CLOSE_AND_WAIT(process1);
+
+	test.Next(_L("Attempt read/write 1"));
+	r = process1.Create(RProcess().FileName(), KTestParamRw);
+	test_KErrNone(r);
+	process1.Logon(rs);
+	process1.Resume();
+	User::WaitForRequest(rs);
+	test_Equal(EExitPanic, process1.ExitType());
+	test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
+	CLOSE_AND_WAIT(process1);
+	// Controlling process is not affected
+	TUint8* write = chunk.Base();
+	*write = 0x77;
+
+	test.Next(_L("Attempt read/write 2"));
+	test_Equal(EExitPending, process2.ExitType());
+	process2.Logon(rs);
+	sem.Signal();
+	User::WaitForRequest(rs);
+	test_Equal(EExitPanic, process2.ExitType());
+	test_Equal(3, process2.ExitReason()); // KERN-EXEC 3 assumed
+	CLOSE_AND_WAIT(process2);
+
+	chunk.Close();
+	sem.Close();
+	test.End();
+	User::SetJustInTime(jit);
+	}
 
 TInt E32Main()
 //
@@ -1180,15 +1357,38 @@
 	test(l.CancelLazyDllUnload()==KErrNone);
 	l.Close();
 
-	__KHEAP_MARK;
+	_LIT(KExtended,"extended");
 
-	if (GetExtended() ) 
+	if (IsInCommandLine(KExtended))
+		{
+		__KHEAP_MARK;
+		test.Printf(_L("t_chunk extended was called. Ready to call TestFullAddressSpace(Etrue) \n"));
+		TestFullAddressSpace(ETrue);
+		__KHEAP_MARKEND;
+		}
+	else if (IsInCommandLine(KTestParamRo))
 		{
-		test.Printf(_L("t_chunk extended was called. Ready to call TestFullAddressSpace(Etrue) \n"));
-		TestFullAddressSpace(ETrue);	
-		}	
+		test_KErrNone(User::RenameProcess(KTestParamRo));
+		TestReadOnlyProcess(0);
+		}
+	else if (IsInCommandLine(KTestParamRw))
+		{
+		test_KErrNone(User::RenameProcess(KTestParamRw));
+		TestReadOnlyProcess(ETestRw);
+		}
+	else if (IsInCommandLine(KTestParamWait))
+		{
+		test_KErrNone(User::RenameProcess(KTestParamWait));
+		TestReadOnlyProcess(ETestRw | ETestWait);
+		}
+	else if (IsInCommandLine(KTestParamWritableChunk))
+		{
+		test_KErrNone(User::RenameProcess(KTestParamWritableChunk));
+		TestReadOnlyProcess(ETestWritableChunk | ETestRw);
+		}
 	else 
 		{
+		__KHEAP_MARK;
 		test.Start(_L("Testing.."));
 		testAdjustChunk();
 		test.Next(_L("Test1"));
@@ -1223,12 +1423,12 @@
 
 		test.Next(_L("Test for race conditions in chunk closure"));
 		TestClosure();
+		test.Next(_L("Read-only chunks"));
+		TestReadOnly();
 		test.End();
-		}	
+		__KHEAP_MARKEND;
+		}
 
 	test.Close();
-	__KHEAP_MARKEND;
-	
-	
 	return(KErrNone);
 	}