|
1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32test\system\t_prot.cpp |
|
15 // Overview: |
|
16 // Tests that the kernel panics the user rather than dying in |
|
17 // various situations |
|
18 // API Information: |
|
19 // N/A |
|
20 // Details: |
|
21 // - Verify that printing a long string does not panic. |
|
22 // - Verify that a stack overflow in a thread causes a panic. |
|
23 // - Create the thread which panics a dead thread, verify that |
|
24 // it isn't panicked for doing this. |
|
25 // - Create the thread which panics a bad handle, verify that |
|
26 // it isn't panicked for doing this. |
|
27 // - Verify that an RSession send from an uninitialised handle |
|
28 // causes a panic. |
|
29 // - Verify that the thread causing an exception, for a variety |
|
30 // of reasons, is panicked. |
|
31 // - Verify thread writing to kernel data is panicked. |
|
32 // - Verify that RAM disk access either causes a panic or is |
|
33 // denied, based on the platform security settings. |
|
34 // - Verify that an RThread::RequestComplete() with an invalid |
|
35 // address causes a panic. Verify results are as expected. |
|
36 // Platforms/Drives/Compatibility: |
|
37 // All. |
|
38 // Assumptions/Requirement/Pre-requisites: |
|
39 // Failures and causes: |
|
40 // Base Port information: |
|
41 // |
|
42 // |
|
43 |
|
44 #include <e32test.h> |
|
45 #include "u32std.h" |
|
46 #include <e32panic.h> |
|
47 #include "../mmu/mmudetect.h" |
|
48 |
|
49 void DoUndefinedInstruction(); |
|
50 |
|
51 const TInt KHeapSize=0x200; |
|
52 const TInt KThreadReturnValue=9999; |
|
53 |
|
54 _LIT(KLitKernExec,"KERN-EXEC"); |
|
55 |
|
56 class RSessionTest : public RSessionBase |
|
57 { |
|
58 public: |
|
59 void DoSend(); |
|
60 }; |
|
61 |
|
62 |
|
63 void RSessionTest::DoSend() |
|
64 { |
|
65 Send(34,TIpcArgs(78)); |
|
66 //Send(34,(TAny*)78); |
|
67 }; |
|
68 |
|
69 LOCAL_D RTest test(_L("T_PROT")); |
|
70 LOCAL_D RTest t(_L("T_PROT thread")); |
|
71 |
|
72 enum TAction |
|
73 { |
|
74 EDataAbort=0, |
|
75 EPrefetchAbort=1, |
|
76 EUndefinedInstruction=2, |
|
77 }; |
|
78 |
|
79 typedef void (*PFV)(void); |
|
80 |
|
81 #ifndef __MARM__ |
|
82 void DoUndefinedInstruction() |
|
83 { |
|
84 #ifdef __GCC32__ |
|
85 asm("int 6"); |
|
86 #else |
|
87 _asm int 6; |
|
88 #endif |
|
89 } |
|
90 #endif |
|
91 |
|
92 LOCAL_C TInt ExceptionThread(TAny* anAction) |
|
93 { |
|
94 TAction action=(TAction)((TInt) anAction); |
|
95 switch (action) |
|
96 { |
|
97 case EDataAbort: |
|
98 *(TInt*)0=0; |
|
99 break; |
|
100 case EPrefetchAbort: |
|
101 { |
|
102 // PFV f=(PFV)NULL; |
|
103 PFV f=(PFV)0x80000; // don't use NULL since it is readable on Snowdrop |
|
104 (*f)(); |
|
105 break; |
|
106 } |
|
107 case EUndefinedInstruction: |
|
108 DoUndefinedInstruction(); |
|
109 break; |
|
110 }; |
|
111 return 0; |
|
112 } |
|
113 |
|
114 LOCAL_C void RunTestThread(TAction anAction) |
|
115 { |
|
116 RThread t; |
|
117 TInt r=t.Create(_L("TestThread"),ExceptionThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)anAction); |
|
118 test(r==KErrNone); |
|
119 TRequestStatus s; |
|
120 t.Logon(s); |
|
121 test(s==KRequestPending); |
|
122 t.Resume(); |
|
123 User::WaitForRequest(s); |
|
124 test(t.ExitType()==EExitPanic); |
|
125 test(t.ExitCategory()==_L("KERN-EXEC")); |
|
126 test(t.ExitReason()==ECausedException); |
|
127 CLOSE_AND_WAIT(t); |
|
128 } |
|
129 |
|
130 LOCAL_C TInt UnintThread(TAny* ) |
|
131 { |
|
132 |
|
133 RSessionTest rsb; |
|
134 rsb.DoSend(); |
|
135 FOREVER |
|
136 ; |
|
137 } |
|
138 |
|
139 void testSession() |
|
140 // |
|
141 // Test 1 |
|
142 // |
|
143 { |
|
144 |
|
145 RThread thread; |
|
146 TRequestStatus stat; |
|
147 |
|
148 test.Next(_L("Create UnintThread")); |
|
149 TInt r=thread.Create(_L("UnintThread"),UnintThread,KDefaultStackSize,KHeapSize,KHeapSize,0); |
|
150 test(r==KErrNone); |
|
151 |
|
152 thread.Logon(stat); |
|
153 test(thread.ExitType()==EExitPending); |
|
154 test.Next(_L("Resume UnintThread")); |
|
155 thread.Resume(); |
|
156 User::WaitForRequest(stat); |
|
157 test.Next(_L("Check UnintThread panicked")); |
|
158 test(thread.ExitCategory()==_L("KERN-EXEC")); |
|
159 // test(thread.ExitReason()==EBadHandle); |
|
160 test(thread.ExitType()==EExitPanic); |
|
161 CLOSE_AND_WAIT(thread); |
|
162 } |
|
163 |
|
164 TInt dummy(TAny*) |
|
165 { |
|
166 return(KErrNone); |
|
167 } |
|
168 |
|
169 // Dennis - modified this to panic a dead thread rather than a bad handle |
|
170 TInt pdThread(TAny*) |
|
171 { |
|
172 RThread thread; |
|
173 TRequestStatus stat; |
|
174 TInt r=thread.Create(_L("dummy"),dummy,KDefaultStackSize,KHeapSize,KHeapSize,0); |
|
175 test(r==KErrNone); |
|
176 thread.Logon(stat); |
|
177 test(thread.ExitType()==EExitPending); |
|
178 thread.Resume(); |
|
179 User::WaitForRequest(stat); |
|
180 test(thread.ExitType()==EExitKill); |
|
181 test(stat.Int()==KErrNone); |
|
182 thread.Panic(_L("MYPANIC"),0x666); // this shouldn't panic pdThread |
|
183 test(thread.ExitType()==EExitKill); |
|
184 test(thread.ExitReason()==KErrNone); |
|
185 CLOSE_AND_WAIT(thread); |
|
186 return(KErrNone); |
|
187 } |
|
188 |
|
189 void testPanicDeadThread() |
|
190 // |
|
191 // Dennis - modified this to panic a dead thread rather than a bad handle |
|
192 // Create the thread which panics a dead thread /*bad handle*/ |
|
193 // Check that it isn't panicked for doing this |
|
194 // |
|
195 { |
|
196 RThread thread; |
|
197 TRequestStatus stat; |
|
198 test.Next(_L("Create PanicDeadThread")); |
|
199 TInt r=thread.Create(_L("PanicDeadThread"),pdThread,KDefaultStackSize,KHeapSize,KHeapSize,0); |
|
200 test(r==KErrNone); |
|
201 thread.Logon(stat); |
|
202 test(thread.ExitType()==EExitPending); |
|
203 test.Next(_L("Resume PanicDeadThread")); |
|
204 thread.Resume(); |
|
205 User::WaitForRequest(stat); |
|
206 test.Next(_L("Check PanicDeadThread did not panic")); |
|
207 test(thread.ExitReason()==KErrNone); |
|
208 test(thread.ExitType()==EExitKill); |
|
209 test(thread.ExitCategory()==_L("Kill")); |
|
210 CLOSE_AND_WAIT(thread); |
|
211 } |
|
212 |
|
213 TInt doDeadThreadStuff(TAny*) |
|
214 { |
|
215 RThread thread; |
|
216 TRequestStatus stat; |
|
217 TInt r=thread.Create(_L("dummy2"),dummy,KDefaultStackSize,KHeapSize,KHeapSize,0); |
|
218 test(r==KErrNone); |
|
219 thread.Logon(stat); |
|
220 test(thread.ExitType()==EExitPending); |
|
221 thread.Resume(); |
|
222 User::WaitForRequest(stat); |
|
223 |
|
224 thread.SetPriority(EPriorityNormal); |
|
225 |
|
226 CLOSE_AND_WAIT(thread); |
|
227 return(KErrNone); |
|
228 } |
|
229 |
|
230 void testDeadThread() |
|
231 // |
|
232 // Create the thread which panics a bad handle |
|
233 // Check that it isn't panicked for doing this |
|
234 // |
|
235 { |
|
236 RThread thread; |
|
237 TRequestStatus stat; |
|
238 test.Next(_L("Create doDeadThreadStuff")); |
|
239 TInt r=thread.Create(_L("doDeadThreadStuff"),doDeadThreadStuff,KDefaultStackSize,KHeapSize,KHeapSize,0); |
|
240 test(r==KErrNone); |
|
241 thread.Logon(stat); |
|
242 test(thread.ExitType()==EExitPending); |
|
243 test.Next(_L("Resume doDeadThreadStuff")); |
|
244 thread.Resume(); |
|
245 User::WaitForRequest(stat); |
|
246 test.Next(_L("Check doDeadThreadStuff did not panic")); |
|
247 test(thread.ExitReason()==KErrNone); |
|
248 test(thread.ExitType()==EExitKill); |
|
249 test(thread.ExitCategory()==_L("Kill")); |
|
250 CLOSE_AND_WAIT(thread); |
|
251 } |
|
252 |
|
253 TInt MinimalThread(TAny*) |
|
254 // |
|
255 // Minimal thread, used in test 5 |
|
256 // |
|
257 { |
|
258 return(KErrNone); |
|
259 } |
|
260 |
|
261 LOCAL_C TInt ExceptThread(TAny* ) |
|
262 { |
|
263 |
|
264 TUint* nullPtr=0; |
|
265 *nullPtr=0xdead; // BANG!! |
|
266 return KErrNone; |
|
267 } |
|
268 |
|
269 |
|
270 void testExcept() |
|
271 // |
|
272 // Test thread causing exception is panicked |
|
273 // |
|
274 { |
|
275 |
|
276 RThread thread; |
|
277 TRequestStatus stat; |
|
278 |
|
279 test.Next(_L("Create ExceptThread")); |
|
280 TInt r=thread.Create(_L("ExceptThread"),ExceptThread,KDefaultStackSize,KHeapSize,KHeapSize,0); |
|
281 test(r==KErrNone); |
|
282 |
|
283 thread.Logon(stat); |
|
284 test(thread.ExitType()==EExitPending); |
|
285 test.Next(_L("Resume ExceptThread")); |
|
286 thread.Resume(); |
|
287 User::WaitForRequest(stat); |
|
288 test.Next(_L("Check ExceptThread panicked")); |
|
289 test(thread.ExitCategory()==_L("KERN-EXEC")); |
|
290 test(thread.ExitReason()==ECausedException); |
|
291 test(thread.ExitType()==EExitPanic); |
|
292 CLOSE_AND_WAIT(thread); |
|
293 } |
|
294 |
|
295 LOCAL_C TInt StackThread(TAny* ) |
|
296 { |
|
297 |
|
298 TFileName heresAnotherOne; |
|
299 StackThread((TAny*)heresAnotherOne.Ptr()); // go recursive |
|
300 return KErrNone; |
|
301 } |
|
302 |
|
303 void testStackOverflow() |
|
304 // |
|
305 // Thread overflowing its stack is panicked |
|
306 // |
|
307 { |
|
308 |
|
309 RThread thread; |
|
310 TRequestStatus stat; |
|
311 |
|
312 test.Next(_L("Create StackThread")); |
|
313 TInt r=thread.Create(_L("StackThread"),StackThread,KDefaultStackSize,KHeapSize,KHeapSize,0); |
|
314 test(r==KErrNone); |
|
315 |
|
316 thread.Logon(stat); |
|
317 test(thread.ExitType()==EExitPending); |
|
318 test.Next(_L("Resume StackThread")); |
|
319 thread.Resume(); |
|
320 User::WaitForRequest(stat); |
|
321 test.Next(_L("Check StackThread panicked")); |
|
322 test(thread.ExitCategory()==_L("KERN-EXEC")); |
|
323 test(thread.ExitReason()==ECausedException); |
|
324 test(thread.ExitType()==EExitPanic); |
|
325 CLOSE_AND_WAIT(thread); |
|
326 } |
|
327 |
|
328 LOCAL_C TInt KernWriter(TAny* ) |
|
329 { |
|
330 |
|
331 TUint* kernPtr=(TUint*)KernData(); |
|
332 *kernPtr=0xdead; // BANG!! |
|
333 return KErrNone; |
|
334 } |
|
335 |
|
336 LOCAL_C TInt RamDiskWriter(TAny* ) |
|
337 { |
|
338 |
|
339 TFindChunk fChunk(_L("*TheRamDriveChunk*")); |
|
340 TFullName n; |
|
341 TInt r=fChunk.Next(n); |
|
342 RChunk ch; |
|
343 r=ch.Open(fChunk); |
|
344 if(r!=KErrNone) |
|
345 return r; |
|
346 TUint8* rdPtr=ch.Base(); |
|
347 *rdPtr=0xaa; // BANG!! |
|
348 return KErrNone; |
|
349 } |
|
350 |
|
351 |
|
352 void testKernelWriter() |
|
353 // |
|
354 // Thread writing to kernel data is panicked |
|
355 // |
|
356 { |
|
357 |
|
358 RThread thread; |
|
359 TRequestStatus stat; |
|
360 |
|
361 test.Next(_L("Create KernWriter")); |
|
362 TInt r=thread.Create(_L("KernWriter"),KernWriter,KDefaultStackSize,KHeapSize,KHeapSize,0); |
|
363 test(r==KErrNone); |
|
364 |
|
365 thread.Logon(stat); |
|
366 test(thread.ExitType()==EExitPending); |
|
367 test.Next(_L("Resume KernWriter")); |
|
368 thread.Resume(); |
|
369 User::WaitForRequest(stat); |
|
370 test.Next(_L("Check KernWriter panicked")); |
|
371 test(thread.ExitCategory()==_L("KERN-EXEC")); |
|
372 test(thread.ExitReason()==ECausedException); |
|
373 test(thread.ExitType()==EExitPanic); |
|
374 CLOSE_AND_WAIT(thread); |
|
375 } |
|
376 |
|
377 void testRamDiskAccess() |
|
378 { |
|
379 |
|
380 RThread thread; |
|
381 TRequestStatus stat; |
|
382 |
|
383 test.Next(_L("Create RamDiskWriter")); |
|
384 TInt r=thread.Create(_L("RamDiskWriter"),RamDiskWriter,KDefaultStackSize,KHeapSize,KHeapSize,0); |
|
385 test(r==KErrNone); |
|
386 |
|
387 thread.Logon(stat); |
|
388 test(thread.ExitType()==EExitPending); |
|
389 test.Next(_L("Resume RamDiskWriter")); |
|
390 thread.Resume(); |
|
391 User::WaitForRequest(stat); |
|
392 if((!PlatSec::ConfigSetting(PlatSec::EPlatSecProcessIsolation))||(!PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement))) |
|
393 { |
|
394 test.Next(_L("Check RamDiskWriter panicked")); |
|
395 test(thread.ExitCategory()==_L("KERN-EXEC")); |
|
396 test(thread.ExitReason()==ECausedException); |
|
397 test(thread.ExitType()==EExitPanic); |
|
398 } |
|
399 else |
|
400 { |
|
401 test.Next(_L("Check RamDiskWriter was refused access")); |
|
402 test(thread.ExitReason()==KErrPermissionDenied); |
|
403 test(thread.ExitType()==EExitKill); |
|
404 } |
|
405 CLOSE_AND_WAIT(thread); |
|
406 } |
|
407 |
|
408 RThread MainThread; |
|
409 |
|
410 TInt RequestCompleteThread(TAny* aPtr) |
|
411 { |
|
412 TRequestStatus** pS=(TRequestStatus**)aPtr; |
|
413 MainThread.RequestComplete(*pS,123); |
|
414 return 0; |
|
415 } |
|
416 |
|
417 _LIT(KReqCompThreadName,"ReqCompThread"); |
|
418 void StartRequestCompleteThread(RThread& aThread, TRequestStatus** aStatus) |
|
419 { |
|
420 TInt r=aThread.Create(KReqCompThreadName,RequestCompleteThread,0x1000,0x1000,0x10000,aStatus); |
|
421 test (r==KErrNone); |
|
422 aThread.SetPriority(EPriorityMore); |
|
423 TRequestStatus s; |
|
424 aThread.Logon(s); |
|
425 aThread.Resume(); |
|
426 User::WaitForRequest(s); |
|
427 } |
|
428 |
|
429 _LIT(KLitUserCBase,"E32USER-CBase"); |
|
430 GLDEF_C TInt E32Main() |
|
431 // |
|
432 // Main |
|
433 // |
|
434 { |
|
435 |
|
436 // don't want just in time debugging as we trap panics |
|
437 TBool justInTime=User::JustInTime(); |
|
438 User::SetJustInTime(EFalse); |
|
439 |
|
440 test.Title(); |
|
441 test.Start(_L("Test protection & panicking")); |
|
442 |
|
443 #if defined(__EPOC32__) |
|
444 // this next test doesn't work under WINS because the string needs to be converted |
|
445 // from UNICODE to ascii for printing to STDOUT, and that requires the string to be |
|
446 // zero-terminated which panics because the string is too long. |
|
447 test.Next(_L("Printing long string doesn't get me shot")); |
|
448 test.Printf(_L("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")); |
|
449 test.Printf(_L("\n")); |
|
450 #endif |
|
451 |
|
452 if (HaveVirtMem()) |
|
453 { |
|
454 test.Next(_L("Stack overflow shoots the thread not the kernel")); |
|
455 testStackOverflow(); |
|
456 } |
|
457 |
|
458 test.Next(_L("Panicking a closed thread doesn't panic the panicker!!")); |
|
459 testPanicDeadThread(); |
|
460 |
|
461 test.Next(_L("Dead thread tests")); |
|
462 testDeadThread(); |
|
463 |
|
464 test.Next(_L("RSession send from uninitialised handle")); |
|
465 testSession(); |
|
466 |
|
467 test.Next(_L("Thread causing exception is killed")); |
|
468 if (HaveVirtMem()) |
|
469 { |
|
470 testExcept(); |
|
471 RunTestThread(EDataAbort); |
|
472 RunTestThread(EPrefetchAbort); |
|
473 } |
|
474 #ifndef __WINS__ |
|
475 RunTestThread(EUndefinedInstruction); |
|
476 #endif |
|
477 |
|
478 #if defined(__EPOC32__) |
|
479 if (HaveDirectKernProt()) |
|
480 { |
|
481 test.Next(_L("Thread writing to kernel data is killed")); |
|
482 testKernelWriter(); |
|
483 } |
|
484 |
|
485 if (HaveProcessProt()) |
|
486 { |
|
487 test.Next(_L("Check access to RamDisk is denied")); |
|
488 testRamDiskAccess(); |
|
489 } |
|
490 |
|
491 if (HaveMMU()) |
|
492 { |
|
493 test.Next(_L("RequestComplete() with bad address")); |
|
494 TInt rqc=RThread().RequestCount(); |
|
495 test(MainThread.Duplicate(RThread())==KErrNone); |
|
496 RThread t; |
|
497 TRequestStatus s=KRequestPending; |
|
498 TRequestStatus* pS=&s; |
|
499 StartRequestCompleteThread(t,&pS); |
|
500 test(t.ExitType()==EExitKill); |
|
501 test(t.ExitReason()==KErrNone); |
|
502 CLOSE_AND_WAIT(t); |
|
503 test(s==123); |
|
504 test(pS==NULL); |
|
505 test(RThread().RequestCount()==rqc+1); |
|
506 TRequestStatus** bad=(TRequestStatus**)0x80000000; // kernel space |
|
507 StartRequestCompleteThread(t,bad); |
|
508 test(t.ExitType()==EExitPanic); |
|
509 test(t.ExitReason()==ECausedException); |
|
510 test(t.ExitCategory()==KLitKernExec); |
|
511 CLOSE_AND_WAIT(t); |
|
512 test(RThread().RequestCount()==rqc+1); |
|
513 pS=(TRequestStatus*)0x80000000; |
|
514 StartRequestCompleteThread(t,&pS); |
|
515 // Request status poked user side, so we expect a KERN-EXEC 3... |
|
516 test(t.ExitType()==EExitPanic); |
|
517 test(t.ExitReason()==ECausedException); |
|
518 test(t.ExitCategory()==KLitKernExec); |
|
519 CLOSE_AND_WAIT(t); |
|
520 test(pS==NULL); |
|
521 test(RThread().RequestCount()==rqc+1); |
|
522 pS=(TRequestStatus*)(((TUint8*)&s)+0x80000); // aligned, within chunk max size but invalid |
|
523 StartRequestCompleteThread(t,&pS); |
|
524 // Request status poked user side, so we expect a KERN-EXEC 3... |
|
525 test(t.ExitType()==EExitPanic); |
|
526 test(t.ExitReason()==ECausedException); |
|
527 test(t.ExitCategory()==KLitKernExec); |
|
528 CLOSE_AND_WAIT(t); |
|
529 test(pS==NULL); |
|
530 test(RThread().RequestCount()==rqc+1); |
|
531 } |
|
532 #endif |
|
533 |
|
534 test.End(); |
|
535 |
|
536 User::SetJustInTime(justInTime); |
|
537 return(KErrNone); |
|
538 } |
|
539 |