Force 16 byte stack alignment on JNI method invocations on x86

Reviewed By: dcolascione

Differential Revision: D2989293

fb-gh-sync-id: 9140ced55ef0b8a73fdc03a6d307af87cd2335ef
shipit-source-id: 9140ced55ef0b8a73fdc03a6d307af87cd2335ef
This commit is contained in:
Michał Gregorczyk 2016-03-02 07:23:47 -08:00 committed by Facebook Github Bot 1
parent d3f2081d90
commit 5df3eeb723
4 changed files with 36 additions and 58 deletions

View File

@ -1,15 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#ifdef __i386__
// The Android x86 ABI states that the NDK toolchain assumes 16 byte stack
// alignment: http://developer.android.com/ndk/guides/x86.html JSC checks for
// stack alignment, and fails with SIGTRAP if it is not. Empirically, the
// google android x86 emulator does not provide this alignment, and so JSC
// calls may crash. All checked calls go through here, so the attribute here
// is added to force alignment and prevent crashes.
#define ALIGN_STACK __attribute__((force_align_arg_pointer))
#else
#define ALIGN_STACK
#endif

View File

@ -65,7 +65,6 @@ react_library(
'JSCMemory.h', 'JSCMemory.h',
], ],
exported_headers = [ exported_headers = [
'AlignStack.h',
'Bridge.h', 'Bridge.h',
'ExecutorToken.h', 'ExecutorToken.h',
'ExecutorTokenFactory.h', 'ExecutorTokenFactory.h',

View File

@ -9,8 +9,6 @@
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include "AlignStack.h"
namespace facebook { namespace facebook {
namespace react { namespace react {
@ -18,13 +16,11 @@ struct JsException : std::runtime_error {
using std::runtime_error::runtime_error; using std::runtime_error::runtime_error;
}; };
ALIGN_STACK
inline void throwJSExecutionException(const char* msg) { inline void throwJSExecutionException(const char* msg) {
throw JsException(msg); throw JsException(msg);
} }
template <typename... Args> template <typename... Args>
ALIGN_STACK
inline void throwJSExecutionException(const char* fmt, Args... args) { inline void throwJSExecutionException(const char* fmt, Args... args) {
int msgSize = snprintf(nullptr, 0, fmt, args...); int msgSize = snprintf(nullptr, 0, fmt, args...);
msgSize = std::min(512, msgSize + 1); msgSize = std::min(512, msgSize + 1);
@ -36,16 +32,16 @@ inline void throwJSExecutionException(const char* fmt, Args... args) {
void installGlobalFunction( void installGlobalFunction(
JSGlobalContextRef ctx, JSGlobalContextRef ctx,
const char* name, const char* name,
JSObjectCallAsFunctionCallback callback) ALIGN_STACK; JSObjectCallAsFunctionCallback callback);
JSValueRef makeJSCException( JSValueRef makeJSCException(
JSContextRef ctx, JSContextRef ctx,
const char* exception_text) ALIGN_STACK; const char* exception_text);
JSValueRef evaluateScript( JSValueRef evaluateScript(
JSContextRef ctx, JSContextRef ctx,
JSStringRef script, JSStringRef script,
JSStringRef sourceURL, JSStringRef sourceURL,
const char* cachePath = nullptr) ALIGN_STACK; const char* cachePath = nullptr);
} } } }

View File

@ -14,8 +14,6 @@
#include "noncopyable.h" #include "noncopyable.h"
#include "AlignStack.h"
#if WITH_FBJSCEXTENSIONS #if WITH_FBJSCEXTENSIONS
#include <jsc_stringref.h> #include <jsc_stringref.h>
#endif #endif
@ -28,15 +26,15 @@ class Context;
class String : public noncopyable { class String : public noncopyable {
public: public:
explicit String(const char* utf8) ALIGN_STACK : explicit String(const char* utf8) :
m_string(Adopt, JSStringCreateWithUTF8CString(utf8)) m_string(Adopt, JSStringCreateWithUTF8CString(utf8))
{} {}
String(String&& other) ALIGN_STACK : String(String&& other) :
m_string(Adopt, other.m_string.leakRef()) m_string(Adopt, other.m_string.leakRef())
{} {}
String(const String& other) ALIGN_STACK : String(const String& other) :
m_string(other.m_string) m_string(other.m_string)
{} {}
@ -45,16 +43,16 @@ public:
} }
// Length in characters // Length in characters
size_t length() const ALIGN_STACK { size_t length() const {
return JSStringGetLength(m_string.get()); return JSStringGetLength(m_string.get());
} }
// Length in bytes of a null-terminated utf8 encoded value // Length in bytes of a null-terminated utf8 encoded value
size_t utf8Size() const ALIGN_STACK { size_t utf8Size() const {
return JSStringGetMaximumUTF8CStringSize(m_string.get()); return JSStringGetMaximumUTF8CStringSize(m_string.get());
} }
std::string str() const ALIGN_STACK { std::string str() const {
size_t reserved = utf8Size(); size_t reserved = utf8Size();
char* bytes = new char[reserved]; char* bytes = new char[reserved];
size_t length = JSStringGetUTF8CString(m_string.get(), bytes, reserved) - 1; size_t length = JSStringGetUTF8CString(m_string.get(), bytes, reserved) - 1;
@ -63,11 +61,11 @@ public:
} }
// Assumes that utf8 is null terminated // Assumes that utf8 is null terminated
bool equals(const char* utf8) ALIGN_STACK { bool equals(const char* utf8) {
return JSStringIsEqualToUTF8CString(m_string.get(), utf8); return JSStringIsEqualToUTF8CString(m_string.get(), utf8);
} }
static String createExpectingAscii(std::string const &utf8) ALIGN_STACK { static String createExpectingAscii(std::string const &utf8) {
#if WITH_FBJSCEXTENSIONS #if WITH_FBJSCEXTENSIONS
return String(Adopt, JSStringCreateWithUTF8CStringExpectAscii(utf8.c_str(), utf8.size())); return String(Adopt, JSStringCreateWithUTF8CStringExpectAscii(utf8.c_str(), utf8.size()));
#else #else
@ -84,11 +82,11 @@ public:
} }
private: private:
explicit String(JSStringRef string) ALIGN_STACK : explicit String(JSStringRef string) :
m_string(string) m_string(string)
{} {}
String(AdoptTag tag, JSStringRef string) ALIGN_STACK : String(AdoptTag tag, JSStringRef string) :
m_string(tag, string) m_string(tag, string)
{} {}
@ -110,7 +108,7 @@ public:
other.m_isProtected = false; other.m_isProtected = false;
} }
~Object() ALIGN_STACK { ~Object() {
if (m_isProtected && m_obj) { if (m_isProtected && m_obj) {
JSValueUnprotect(m_context, m_obj); JSValueUnprotect(m_context, m_obj);
} }
@ -122,28 +120,28 @@ public:
operator Value() const; operator Value() const;
bool isFunction() const ALIGN_STACK { bool isFunction() const {
return JSObjectIsFunction(m_context, m_obj); return JSObjectIsFunction(m_context, m_obj);
} }
Value callAsFunction(int nArgs, JSValueRef args[]) ALIGN_STACK; Value callAsFunction(int nArgs, JSValueRef args[]);
Value getProperty(const String& propName) const ALIGN_STACK; Value getProperty(const String& propName) const;
Value getProperty(const char *propName) const; Value getProperty(const char *propName) const;
Value getPropertyAtIndex(unsigned index) const ALIGN_STACK; Value getPropertyAtIndex(unsigned index) const;
void setProperty(const String& propName, const Value& value) const ALIGN_STACK; void setProperty(const String& propName, const Value& value) const;
void setProperty(const char *propName, const Value& value) const; void setProperty(const char *propName, const Value& value) const;
std::vector<std::string> getPropertyNames() const ALIGN_STACK; std::vector<std::string> getPropertyNames() const;
std::unordered_map<std::string, std::string> toJSONMap() const ALIGN_STACK; std::unordered_map<std::string, std::string> toJSONMap() const;
void makeProtected() ALIGN_STACK { void makeProtected() {
if (!m_isProtected && m_obj) { if (!m_isProtected && m_obj) {
JSValueProtect(m_context, m_obj); JSValueProtect(m_context, m_obj);
m_isProtected = true; m_isProtected = true;
} }
} }
static Object getGlobalObject(JSContextRef ctx) ALIGN_STACK { static Object getGlobalObject(JSContextRef ctx) {
auto globalObj = JSContextGetGlobalObject(ctx); auto globalObj = JSContextGetGlobalObject(ctx);
return Object(ctx, globalObj); return Object(ctx, globalObj);
} }
@ -151,7 +149,7 @@ public:
/** /**
* Creates an instance of the default object class. * Creates an instance of the default object class.
*/ */
static Object create(JSContextRef ctx) ALIGN_STACK; static Object create(JSContextRef ctx);
private: private:
JSContextRef m_context; JSContextRef m_context;
@ -168,27 +166,27 @@ public:
return m_value; return m_value;
} }
bool isBoolean() const ALIGN_STACK { bool isBoolean() const {
return JSValueIsBoolean(context(), m_value); return JSValueIsBoolean(context(), m_value);
} }
bool asBoolean() const ALIGN_STACK { bool asBoolean() const {
return JSValueToBoolean(context(), m_value); return JSValueToBoolean(context(), m_value);
} }
bool isNumber() const ALIGN_STACK { bool isNumber() const {
return JSValueIsNumber(context(), m_value); return JSValueIsNumber(context(), m_value);
} }
bool isNull() const ALIGN_STACK { bool isNull() const {
return JSValueIsNull(context(), m_value); return JSValueIsNull(context(), m_value);
} }
bool isUndefined() const ALIGN_STACK { bool isUndefined() const {
return JSValueIsUndefined(context(), m_value); return JSValueIsUndefined(context(), m_value);
} }
double asNumber() const ALIGN_STACK { double asNumber() const {
if (isNumber()) { if (isNumber()) {
return JSValueToNumber(context(), m_value, nullptr); return JSValueToNumber(context(), m_value, nullptr);
} else { } else {
@ -204,22 +202,22 @@ public:
return static_cast<uint32_t>(asNumber()); return static_cast<uint32_t>(asNumber());
} }
bool isObject() const ALIGN_STACK { bool isObject() const {
return JSValueIsObject(context(), m_value); return JSValueIsObject(context(), m_value);
} }
Object asObject() ALIGN_STACK; Object asObject();
bool isString() const ALIGN_STACK { bool isString() const {
return JSValueIsString(context(), m_value); return JSValueIsString(context(), m_value);
} }
String toString() ALIGN_STACK { String toString() {
return String::adopt(JSValueToStringCopy(context(), m_value, nullptr)); return String::adopt(JSValueToStringCopy(context(), m_value, nullptr));
} }
std::string toJSONString(unsigned indent = 0) const ALIGN_STACK; std::string toJSONString(unsigned indent = 0) const;
static Value fromJSON(JSContextRef ctx, const String& json) ALIGN_STACK; static Value fromJSON(JSContextRef ctx, const String& json);
protected: protected:
JSContextRef context() const; JSContextRef context() const;
JSContextRef m_context; JSContextRef m_context;