Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / native_client / tests / exception_test / exception_test.c
1 /*
2  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <pthread.h>
10 #include <setjmp.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "native_client/src/include/elf_constants.h"
17 #include "native_client/src/include/nacl/nacl_exception.h"
18 #include "native_client/src/trusted/service_runtime/include/sys/nacl_syscalls.h"
19 #include "native_client/src/untrusted/nacl/syscall_bindings_trampoline.h"
20 #include "native_client/tests/common/register_set.h"
21 #include "native_client/tests/inbrowser_test_runner/test_runner.h"
22
23
24 /*
25  * This is used for calculating the size of the exception stack frame
26  * when alignment is taken into account.
27  */
28 struct CombinedContext {
29   struct NaClExceptionContext c1;
30   struct NaClExceptionPortableContext c2;
31 };
32
33 char stack[0x10000];
34
35 struct NaClSignalContext g_regs_at_crash;
36 jmp_buf g_jmp_buf;
37
38 char *g_registered_stack;
39 size_t g_registered_stack_size;
40
41
42 #if defined(__mips__)
43 #define STACK_ALIGNMENT 8
44 #else
45 #define STACK_ALIGNMENT 16
46 #endif
47
48 #if defined(__i386__)
49 const int kReturnAddrSize = 4;
50 const int kArgSizeOnStack = 4;
51 const int kRedZoneSize = 0;
52 #elif defined(__x86_64__)
53 const int kReturnAddrSize = 8;
54 const int kArgSizeOnStack = 0;
55 const int kRedZoneSize = 128;
56 #elif defined(__arm__)
57 const int kReturnAddrSize = 0;
58 const int kArgSizeOnStack = 0;
59 const int kRedZoneSize = 0;
60 #elif defined(__mips__)
61 const int kReturnAddrSize = 0;
62 const int kArgSizeOnStack = 16;
63 const int kRedZoneSize = 0;
64 #else
65 # error Unsupported architecture
66 #endif
67
68 void crash_at_known_address(void);
69 extern char prog_ctr_at_crash[];
70 #if defined(__i386__)
71 __asm__(".pushsection .text, \"ax\", @progbits\n"
72         ".p2align 5\n"
73         "crash_at_known_address:\n"
74         "prog_ctr_at_crash:\n"
75         "movl $0, 0\n"
76         ".popsection");
77 #elif defined(__x86_64__)
78 __asm__(".pushsection .text, \"ax\", @progbits\n"
79         ".p2align 5\n"
80         "crash_at_known_address:\n"
81         "prog_ctr_at_crash:\n"
82         "movl $0, (%r15)\n"
83         ".popsection");
84 #elif defined(__arm__)
85 __asm__(".pushsection .text, \"ax\", %progbits\n"
86         ".p2align 4\n"
87         "crash_at_known_address:\n"
88         "mov r0, #0\n"
89         "bic r0, r0, #0xc0000000\n"
90         "prog_ctr_at_crash:\n"
91         "str r0, [r0]\n"
92         ".popsection\n");
93 #elif defined(__mips__)
94 __asm__(".pushsection .text, \"ax\", @progbits\n"
95         ".p2align 4\n"
96         ".global crash_at_known_address\n"
97         "crash_at_known_address:\n"
98         "and $zero, $zero, $t7\n"
99         ".global prog_ctr_at_crash\n"
100         "prog_ctr_at_crash:\n"
101         "sw $t0, 0($zero)\n"
102         ".popsection\n");
103 #else
104 # error Unsupported architecture
105 #endif
106
107
108 void return_from_exception_handler(void) {
109   /*
110    * Clear the exception flag so that future faults will invoke the
111    * exception handler.
112    */
113   int rc = nacl_exception_clear_flag();
114   assert(rc == 0);
115   longjmp(g_jmp_buf, 1);
116 }
117
118 void simple_exception_handler(struct NaClExceptionContext *regs) {
119   return_from_exception_handler();
120 }
121
122 void exception_handler(struct NaClExceptionContext *context);
123 REGS_SAVER_FUNC_NOPROTO(exception_handler, exception_handler_wrapped);
124
125 void exception_handler_wrapped(struct NaClSignalContext *entry_regs) {
126   struct NaClExceptionContext *context =
127       (struct NaClExceptionContext *) RegsGetArg1(entry_regs);
128   struct NaClExceptionPortableContext *portable =
129       nacl_exception_context_get_portable(context);
130
131   printf("handler called\n");
132
133   assert(context->size == (uintptr_t) (portable + 1) - (uintptr_t) context);
134   assert(context->portable_context_size ==
135          sizeof(struct NaClExceptionPortableContext));
136   assert(context->regs_size == sizeof(NaClUserRegisterState));
137
138   assert(portable->stack_ptr == (uint32_t) g_regs_at_crash.stack_ptr);
139   assert(portable->prog_ctr == (uintptr_t) prog_ctr_at_crash);
140 #if defined(__i386__)
141   assert(portable->frame_ptr == g_regs_at_crash.ebp);
142   assert(context->arch == EM_386);
143 #elif defined(__x86_64__)
144   assert(portable->frame_ptr == (uint32_t) g_regs_at_crash.rbp);
145   assert(context->arch == EM_X86_64);
146 #elif defined(__arm__)
147   assert(portable->frame_ptr == g_regs_at_crash.r11);
148   assert(context->arch == EM_ARM);
149   assert(context->regs.r9 == -1);
150 #elif defined(__mips__)
151   assert(portable->frame_ptr == g_regs_at_crash.frame_ptr);
152   assert(context->arch == EM_MIPS);
153 #else
154 # error Unsupported architecture
155 #endif
156
157   /*
158    * Convert the NaClUserRegisterState to a NaClSignalContext so that
159    * we can reuse RegsAssertEqual() to compare the register state.
160    */
161   struct NaClSignalContext reported_regs;
162   RegsCopyFromUserRegisterState(&reported_regs, &context->regs);
163   RegsAssertEqual(&reported_regs, &g_regs_at_crash);
164
165   const int kMaxStackFrameSize = 0x1000;
166   char *stack_top;
167   char local_var;
168   if (g_registered_stack == NULL) {
169     /* Check that our current stack is just below the saved stack pointer. */
170     stack_top = (char *) portable->stack_ptr - kRedZoneSize;
171     assert(stack_top - kMaxStackFrameSize < &local_var);
172     assert(&local_var < stack_top);
173   } else {
174     /* Check that we are running on the exception stack. */
175     stack_top = g_registered_stack + g_registered_stack_size;
176     assert(g_registered_stack <= &local_var);
177     assert(&local_var < stack_top);
178   }
179
180   /* Check the exception handler's initial stack pointer more exactly. */
181   uintptr_t frame_base = entry_regs->stack_ptr + kReturnAddrSize;
182   assert(frame_base % STACK_ALIGNMENT == 0);
183   char *frame_top = (char *) (frame_base + kArgSizeOnStack +
184                               sizeof(struct CombinedContext));
185   /* Check that no more than the stack alignment size is wasted. */
186   assert(stack_top - STACK_ALIGNMENT < frame_top);
187   assert(frame_top <= stack_top);
188
189 #if defined(__x86_64__)
190   /* Check that %rsp and %rbp have safe, %r15-extended values. */
191   assert(entry_regs->stack_ptr >> 32 == entry_regs->r15 >> 32);
192   assert(entry_regs->rbp >> 32 == entry_regs->r15 >> 32);
193 #endif
194
195   return_from_exception_handler();
196 }
197
198 void test_exception_stack_with_size(char *stack, size_t stack_size) {
199   if (0 != nacl_exception_set_handler(exception_handler)) {
200     printf("failed to set exception handler\n");
201     exit(4);
202   }
203   if (0 != nacl_exception_set_stack(stack, stack_size)) {
204     printf("failed to set alt stack\n");
205     exit(5);
206   }
207   g_registered_stack = stack;
208   g_registered_stack_size = stack_size;
209
210   char crash_stack[0x1000];
211   RegsFillTestValues(&g_regs_at_crash, /* seed= */ 0);
212   g_regs_at_crash.stack_ptr = (uintptr_t) crash_stack + sizeof(crash_stack);
213   g_regs_at_crash.prog_ctr = (uintptr_t) prog_ctr_at_crash;
214   RegsApplySandboxConstraints(&g_regs_at_crash);
215 #if defined(__arm__)
216   /* crash_at_known_address clobbers r0. */
217   g_regs_at_crash.r0 = 0;
218 #endif
219
220   if (!setjmp(g_jmp_buf)) {
221     JUMP_WITH_REGS(&g_regs_at_crash, crash_at_known_address);
222   }
223   /* Clear the jmp_buf to prevent it from being reused accidentally. */
224   memset(g_jmp_buf, 0, sizeof(g_jmp_buf));
225 }
226
227 void test_exceptions_minimally(void) {
228   /* Test exceptions without having an exception stack set up. */
229   test_exception_stack_with_size(NULL, 0);
230
231   test_exception_stack_with_size(stack, sizeof(stack));
232 }
233
234 void test_exception_stack_alignments(void) {
235   /*
236    * Test the stack realignment logic by trying stacks which end at
237    * different addresses modulo the stack alignment size.
238    */
239   int diff;
240   for (diff = 0; diff <= STACK_ALIGNMENT * 2; diff++) {
241     test_exception_stack_with_size(stack, sizeof(stack) - diff);
242   }
243 }
244
245 void test_getting_previous_handler(void) {
246   /*
247    * The direct IRT call and NaCl syscall exposes old handler as API
248    * whereas nacl_exception_set_handler() does not. This test
249    * exercises that path.
250    */
251   int rc;
252   nacl_exception_handler_t prev_handler;
253
254   rc = NACL_SYSCALL(exception_handler)(exception_handler, NULL);
255   assert(rc == 0);
256
257   rc = NACL_SYSCALL(exception_handler)(NULL, &prev_handler);
258   assert(rc == 0);
259   assert(prev_handler == exception_handler);
260
261   rc = NACL_SYSCALL(exception_handler)(NULL, &prev_handler);
262   assert(rc == 0);
263   assert(prev_handler == NULL);
264 }
265
266 void test_invalid_handlers(void) {
267   int rc;
268   nacl_exception_handler_t unaligned_func_ptr =
269     (nacl_exception_handler_t) ((uintptr_t) exception_handler + 1);
270   const char *ptr_in_rodata_segment = "";
271
272   /* An alignment check is required for safety in all NaCl sandboxes. */
273   rc = nacl_exception_set_handler(unaligned_func_ptr);
274   assert(rc == EFAULT);
275
276   /* A range check is required for safety in the NaCl ARM sandbox. */
277   rc = nacl_exception_set_handler(
278       (nacl_exception_handler_t) (uintptr_t) ptr_in_rodata_segment);
279   assert(rc == EFAULT);
280 }
281
282
283 void *thread_func(void *unused_arg) {
284   /*
285    * This tests that the exception handler gets the correct
286    * NaClAppThread for this thread.  If it gets the wrong thread, the
287    * handler will detect that the stack it is running on does not
288    * match the stack that was registered.
289    *
290    * On x86-64 Windows, it is non-trivial for an out-of-process
291    * exception handler to determine the NaClAppThread for a faulting
292    * thread, which is why we need a test for this.
293    */
294   test_exception_stack_with_size(NULL, 0);
295   test_exception_stack_with_size(stack, sizeof(stack));
296   return NULL;
297 }
298
299 void test_exceptions_on_non_main_thread(void) {
300   pthread_t tid;
301   int rc = pthread_create(&tid, NULL, thread_func, NULL);
302   assert(rc == 0);
303   rc = pthread_join(tid, NULL);
304   assert(rc == 0);
305 }
306
307 void test_catching_various_exception_types(void) {
308   int rc = nacl_exception_set_handler(simple_exception_handler);
309   assert(rc == 0);
310
311   printf("Testing __builtin_trap()...\n");
312   if (!setjmp(g_jmp_buf)) {
313     __builtin_trap();
314     exit(1);
315   }
316
317 #if defined(__i386__) || defined(__x86_64__)
318   printf("Testing hlt...\n");
319   if (!setjmp(g_jmp_buf)) {
320     __asm__("hlt");
321     exit(1);
322   }
323   printf("Testing ud2a (an illegal instruction)...\n");
324   if (!setjmp(g_jmp_buf)) {
325     __asm__("ud2a");
326     exit(1);
327   }
328   printf("Testing integer division by zero...\n");
329   if (!setjmp(g_jmp_buf)) {
330     uint32_t result;
331     __asm__ volatile("idivb %1"
332                      : "=a"(result)
333                      : "r"((uint8_t) 0), "a"((uint16_t) 1));
334     exit(1);
335   }
336 #endif
337
338   /* Clear the jmp_buf to prevent it from being reused accidentally. */
339   memset(g_jmp_buf, 0, sizeof(g_jmp_buf));
340 }
341
342
343 #if defined(__i386__) || defined(__x86_64__)
344
345 int get_x86_direction_flag(void);
346
347 void test_get_x86_direction_flag(void) {
348   /*
349    * Sanity check:  Ensure that get_x86_direction_flag() works.  We
350    * avoid calling assert() with the flag set, because that might not
351    * work.
352    */
353   assert(get_x86_direction_flag() == 0);
354   __asm__("std");
355   int flag = get_x86_direction_flag();
356   __asm__("cld");
357   assert(flag == 1);
358 }
359
360 void direction_flag_exception_handler(struct NaClExceptionContext *context) {
361   assert(get_x86_direction_flag() == 0);
362   return_from_exception_handler();
363 }
364
365 /*
366  * The x86 ABIs require that the x86 direction flag is unset on entry
367  * to a function.  However, a crash could occur while the direction
368  * flag is set.  In order for an exception handler to be a normal
369  * function without x86-specific knowledge, NaCl needs to unset the
370  * direction flag when calling the exception handler.  This test
371  * checks that this happens.
372  */
373 void test_unsetting_x86_direction_flag(void) {
374   int rc = nacl_exception_set_handler(direction_flag_exception_handler);
375   assert(rc == 0);
376   if (!setjmp(g_jmp_buf)) {
377     /* Cause a crash with the direction flag set. */
378     __asm__("std");
379     *((volatile int *) 0) = 0;
380     /* Should not reach here. */
381     exit(1);
382   }
383   /* Clear the jmp_buf to prevent it from being reused accidentally. */
384   memset(g_jmp_buf, 0, sizeof(g_jmp_buf));
385 }
386
387 #endif
388
389
390 void run_test(const char *test_name, void (*test_func)(void)) {
391   printf("Running %s...\n", test_name);
392   test_func();
393 }
394
395 #define RUN_TEST(test_func) (run_test(#test_func, test_func))
396
397 int TestMain(void) {
398   RUN_TEST(test_exceptions_minimally);
399   RUN_TEST(test_exception_stack_alignments);
400   RUN_TEST(test_getting_previous_handler);
401   RUN_TEST(test_invalid_handlers);
402   /* pthread_join() is broken under qemu-arm. */
403   if (getenv("UNDER_QEMU_ARM") == NULL)
404     RUN_TEST(test_exceptions_on_non_main_thread);
405   RUN_TEST(test_catching_various_exception_types);
406
407 #if defined(__i386__) || defined(__x86_64__)
408   RUN_TEST(test_get_x86_direction_flag);
409   RUN_TEST(test_unsetting_x86_direction_flag);
410 #endif
411
412   fprintf(stderr, "** intended_exit_status=0\n");
413   return 0;
414 }
415
416 int main(void) {
417   return RunTests(TestMain);
418 }