Index: ppapi/tests/test_nacl_irt_stack_alignment.cc |
diff --git a/ppapi/tests/test_nacl_irt_stack_alignment.cc b/ppapi/tests/test_nacl_irt_stack_alignment.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5b379c42a3f929b33ba0c331eeb57561a424807b |
--- /dev/null |
+++ b/ppapi/tests/test_nacl_irt_stack_alignment.cc |
@@ -0,0 +1,85 @@ |
+// Copyright (c) 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "ppapi/tests/test_nacl_irt_stack_alignment.h" |
+ |
+#include "ppapi/c/pp_var.h" |
+#include "ppapi/c/ppb_var.h" |
+#include "ppapi/cpp/instance.h" |
+#include "ppapi/cpp/module.h" |
+#include "ppapi/cpp/var.h" |
+#include "ppapi/tests/testing_instance.h" |
+ |
+// This whole test is really only meant for x86-32 NaCl (not PNaCl). |
+// |
+// This is a regression test for the IRT code being sensitive to stack |
+// alignment. The de jure ABI is that the stack should be aligned to |
+// 16 bytes at call sites. However, the de facto ABI is that the IRT |
+// worked in the past when called with misaligned stack. NaCl code is |
+// now compiled to expect the proper 16-byte alignment, but the IRT |
+// code must remain compatible with old binaries that failed to do so. |
+ |
+#if defined(__i386__) |
+ |
+REGISTER_TEST_CASE(NaClIRTStackAlignment); |
+ |
+bool TestNaClIRTStackAlignment::Init() { |
+ var_interface_ = static_cast<const PPB_Var*>( |
+ pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE)); |
+ return var_interface_ && CheckTestingInterface(); |
+} |
+ |
+void TestNaClIRTStackAlignment::RunTests(const std::string& filter) { |
+ RUN_TEST(MisalignedCallVarAddRef, filter); |
+} |
+ |
+// This calls the given function with the stack explicitly misaligned. |
+// If the function (in the IRT) was compiled wrongly, it will crash. |
+void MisalignedCall(void (*func)(PP_Var), const PP_Var* arg) |
+ asm("MisalignedCall") __attribute__((regparm(2))); |
+ |
+// regparm(2) means: First argument in %eax, second argument in %edx. |
+// Writing this with an inline asm would require explaining all the |
+// call-clobbers register behavior in the asm clobber list, which is a |
+// lot with all the SSE and FPU state. It's far simpler just to make |
+// it a function call the compiler knows is a function call, and then |
+// write the function itself in pure assembly. |
+asm("MisalignedCall:\n" |
+ // Use an SSE register to copy the 16 bytes of memory. |
+ // Note this instruction does not care about alignment. |
+ // The pointer is not necessarily aligned to 16 bytes. |
+ "movups (%edx), %xmm0\n" |
+ // Set up a frame so we can recover the stack pointer after alignment. |
+ "push %ebp\n" |
+ "mov %esp, %ebp\n" |
+ // Align the stack properly to 16 bytes. |
+ "andl $-16, %esp\n" |
+ // Now make space for the 16 bytes of argument data, |
+ // plus another 4 bytes so the stack pointer is misaligned. |
+ "subl $20, %esp\n" |
+ // Copy the argument onto the (misaligned) top of stack. |
+ "movups %xmm0, (%esp)\n" |
+ // Now call into the IRT, and hilarity ensues. |
+ "naclcall %eax\n" |
+ // Standard epilogue. |
+ "mov %ebp, %esp\n" |
+ "pop %ebp\n" |
+ "naclret"); |
+ |
+std::string TestNaClIRTStackAlignment::TestMisalignedCallVarAddRef() { |
+ PP_Var var; |
+ var.type = PP_VARTYPE_INT32; |
+ var.padding = 0; |
+ var.value.as_int = 23; |
+ |
+ ASSERT_EQ(sizeof(var), static_cast<size_t>(16)); |
+ |
+ // This will crash if the test fails. |
+ MisalignedCall(var_interface_->AddRef, &var); |
+ MisalignedCall(var_interface_->Release, &var); |
+ |
+ PASS(); |
+} |
+ |
+#endif // defined(__i386__) |