]> git.saurik.com Git - cycript.git/blobdiff - Execute.cpp
Avoid crash when using toCYON on String.prototype.
[cycript.git] / Execute.cpp
index 6581ee1138f0910a02e833ff66cafe17c2f3787a..1c83e26e9252cec2b189c249321e96cf82faca90 100644 (file)
 #include "Pooling.hpp"
 #include "String.hpp"
 
+const char *sqlite3_column_string(sqlite3_stmt *stmt, int n) {
+    return reinterpret_cast<const char *>(sqlite3_column_text(stmt, n));
+}
+
 char *sqlite3_column_pooled(CYPool &pool, sqlite3_stmt *stmt, int n) {
-    if (const unsigned char *value = sqlite3_column_text(stmt, n))
-        return pool.strdup(reinterpret_cast<const char *>(value));
+    if (const char *value = sqlite3_column_string(stmt, n))
+        return pool.strdup(value);
     else return NULL;
 }
 
@@ -150,6 +154,18 @@ size_t CYGetIndex(CYPool &pool, JSContextRef context, JSStringRef value) {
 }
 /* }}} */
 
+static JSObjectRef (*JSObjectMakeArray$)(JSContextRef, size_t, const JSValueRef[], JSValueRef *);
+
+static JSObjectRef CYObjectMakeArray(JSContextRef context, size_t length, const JSValueRef values[]) {
+    if (JSObjectMakeArray$ != NULL)
+        return _jsccall(*JSObjectMakeArray$, context, length, values);
+    else {
+        JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
+        JSValueRef value(CYCallAsFunction(context, Array, NULL, length, values));
+        return CYCastJSObject(context, value);
+    }
+}
+
 static JSClassRef All_;
 static JSClassRef Context_;
 static JSClassRef CString_;
@@ -890,11 +906,6 @@ static bool CString_setProperty(JSContextRef context, JSObjectRef object, JSStri
     return true;
 } CYCatch(false) }
 
-template <typename Type_>
-static void Align(Type_ &data, size_t size) {
-    data = reinterpret_cast<Type_>((reinterpret_cast<uintptr_t>(data) + (size - 1)) & ~(size - 1));
-}
-
 static bool Index_(CYPool &pool, JSContextRef context, Struct_privateData *internal, JSStringRef property, ssize_t &index, uint8_t *&base) {
     Type_privateData *typical(internal->type_);
     sig::Type *type(typical->type_);
@@ -931,13 +942,13 @@ static bool Index_(CYPool &pool, JSContextRef context, Struct_privateData *inter
   base:
     ffi_type **elements(typical->GetFFI()->elements);
 
-    base = reinterpret_cast<uint8_t *>(internal->value_);
+    size_t offset(0);
     for (ssize_t local(0); local != index; ++local) {
-        Align(base, elements[local]->alignment);
-        base += elements[local]->size;
+        offset += elements[local]->size;
+        CYAlign(offset, elements[local + 1]->alignment);
     }
 
-    Align(base, elements[index]->alignment);
+    base = reinterpret_cast<uint8_t *>(internal->value_) + offset;
     return true;
 }
 
@@ -1126,12 +1137,13 @@ JSObjectRef CYMakeType(JSContextRef context, sig::Signature *signature) {
     return CYMakeType(context, &type);
 }
 
-extern "C" const char *CYBridgeHash(CYPool &pool, CYUTF8String name) {
+extern "C" bool CYBridgeHash(CYPool &pool, CYUTF8String name, const char *&code, unsigned &flags) {
     sqlite3_stmt *statement;
 
     _sqlcall(sqlite3_prepare(database_,
         "select "
-            "\"cache\".\"value\" "
+            "\"cache\".\"code\", "
+            "\"cache\".\"flags\" "
         "from \"cache\" "
         "where"
             " \"cache\".\"system\" & " CY_SYSTEM " == " CY_SYSTEM " and"
@@ -1141,17 +1153,23 @@ extern "C" const char *CYBridgeHash(CYPool &pool, CYUTF8String name) {
 
     _sqlcall(sqlite3_bind_text(statement, 1, name.data, name.size, SQLITE_STATIC));
 
-    const char *value;
+    bool success;
     if (_sqlcall(sqlite3_step(statement)) == SQLITE_DONE)
-        value = NULL;
-    else
-        value = sqlite3_column_pooled(pool, statement, 0);
+        success = false;
+    else {
+        success = true;
+        code = sqlite3_column_pooled(pool, statement, 0);
+        flags = sqlite3_column_int(statement, 1);
+    }
 
     _sqlcall(sqlite3_finalize(statement));
-    return value;
+    return success;
 }
 
 static bool All_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
+    if (JSStringIsEqualToUTF8CString(property, "errno"))
+        return true;
+
     JSObjectRef global(CYGetGlobalObject(context));
     JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
     JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
@@ -1162,13 +1180,18 @@ static bool All_hasProperty(JSContextRef context, JSObjectRef object, JSStringRe
                 return true;
 
     CYPool pool;
-    if (CYBridgeHash(pool, CYPoolUTF8String(pool, context, property)) != NULL)
+    const char *code;
+    unsigned flags;
+    if (CYBridgeHash(pool, CYPoolUTF8String(pool, context, property), code, flags))
         return true;
 
     return false;
 }
 
 static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
+    if (JSStringIsEqualToUTF8CString(property, "errno"))
+        return CYCastJSValue(context, errno);
+
     JSObjectRef global(CYGetGlobalObject(context));
     JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
     JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
@@ -1180,15 +1203,72 @@ static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSSt
                     return value;
 
     CYPool pool;
-    if (const char *code = CYBridgeHash(pool, CYPoolUTF8String(pool, context, property))) {
-        JSValueRef result(_jsccall(JSEvaluateScript, context, CYJSString(CYPoolCode(pool, code)), NULL, NULL, 0));
-        CYSetProperty(context, object, property, result, kJSPropertyAttributeDontEnum);
+    const char *code;
+    unsigned flags;
+    if (CYBridgeHash(pool, CYPoolUTF8String(pool, context, property), code, flags)) {
+        CYUTF8String parsed;
+
+        try {
+            parsed = CYPoolCode(pool, code);
+        } catch (const CYException &error) {
+            CYThrow("%s", pool.strcat("error caching ", CYPoolCString(pool, context, property), ": ", error.PoolCString(pool), NULL));
+        }
+
+        JSValueRef result(_jsccall(JSEvaluateScript, context, CYJSString(parsed), NULL, NULL, 0));
+
+        if (flags == 0) {
+            JSObjectRef cache(CYGetCachedObject(context, CYJSString("cache")));
+            CYSetProperty(context, cache, property, result);
+        }
+
         return result;
     }
 
     return NULL;
 } CYCatch(NULL) }
 
+static JSValueRef All_complete_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    _assert(count == 1);
+    CYPool pool;
+    CYUTF8String prefix(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
+
+    std::vector<JSValueRef> values;
+
+    sqlite3_stmt *statement;
+
+    if (prefix.size == 0)
+        _sqlcall(sqlite3_prepare(database_,
+            "select "
+                "\"cache\".\"name\" "
+            "from \"cache\" "
+            "where"
+                " \"cache\".\"system\" & " CY_SYSTEM " == " CY_SYSTEM
+        , -1, &statement, NULL));
+    else {
+        _sqlcall(sqlite3_prepare(database_,
+            "select "
+                "\"cache\".\"name\" "
+            "from \"cache\" "
+            "where"
+                " \"cache\".\"name\" >= ? and \"cache\".\"name\" < ? and "
+                " \"cache\".\"system\" & " CY_SYSTEM " == " CY_SYSTEM
+        , -1, &statement, NULL));
+
+        _sqlcall(sqlite3_bind_text(statement, 1, prefix.data, prefix.size, SQLITE_STATIC));
+
+        char *after(pool.strndup(prefix.data, prefix.size));
+        ++after[prefix.size - 1];
+        _sqlcall(sqlite3_bind_text(statement, 2, after, prefix.size, SQLITE_STATIC));
+    }
+
+    while (_sqlcall(sqlite3_step(statement)) != SQLITE_DONE)
+        values.push_back(CYCastJSValue(context, CYJSString(sqlite3_column_string(statement, 0))));
+
+    _sqlcall(sqlite3_finalize(statement));
+
+    return CYObjectMakeArray(context, values.size(), values.data());
+} CYCatch(NULL) }
+
 static void All_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
     JSObjectRef global(CYGetGlobalObject(context));
     JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
@@ -1673,6 +1753,11 @@ static JSValueRef Type_callAsFunction_toJSON(JSContextRef context, JSObjectRef o
     return Type_callAsFunction_toString(context, object, _this, count, arguments, exception);
 }
 
+static JSStaticFunction All_staticFunctions[2] = {
+    {"cy$complete", &All_complete_callAsFunction, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {NULL, NULL, 0}
+};
+
 static JSStaticFunction CString_staticFunctions[6] = {
     {"toCYON", &CString_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
@@ -1751,23 +1836,13 @@ static JSStaticFunction Type_staticFunctions[14] = {
     {NULL, NULL, 0}
 };
 
-static JSObjectRef (*JSObjectMakeArray$)(JSContextRef, size_t, const JSValueRef[], JSValueRef *);
-
 _visible void CYSetArgs(int argc, const char *argv[]) {
     JSContextRef context(CYGetJSContext());
     JSValueRef args[argc];
     for (int i(0); i != argc; ++i)
         args[i] = CYCastJSValue(context, argv[i]);
 
-    JSObjectRef array;
-    if (JSObjectMakeArray$ != NULL)
-        array = _jsccall(*JSObjectMakeArray$, context, argc, args);
-    else {
-        JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
-        JSValueRef value(CYCallAsFunction(context, Array, NULL, argc, args));
-        array = CYCastJSObject(context, value);
-    }
-
+    JSObjectRef array(CYObjectMakeArray(context, argc, args));
     JSObjectRef System(CYGetCachedObject(context, CYJSString("System")));
     CYSetProperty(context, System, CYJSString("args"), array);
 }
@@ -1857,6 +1932,7 @@ void CYInitializeDynamic() {
 
     definition = kJSClassDefinitionEmpty;
     definition.className = "All";
+    definition.staticFunctions = All_staticFunctions;
     definition.hasProperty = &All_hasProperty;
     definition.getProperty = &All_getProperty;
     definition.getPropertyNames = &All_getPropertyNames;
@@ -1984,53 +2060,6 @@ JSGlobalContextRef CYGetJSContext(JSContextRef context) {
     return reinterpret_cast<Context *>(JSObjectGetPrivate(CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s))))->context_;
 }
 
-struct CYFile {
-    void *data_;
-    size_t size_;
-
-    CYFile(void *data, size_t size) :
-        data_(data),
-        size_(size)
-    {
-    }
-};
-
-static void CYFileExit(void *data) {
-    CYFile *file(reinterpret_cast<CYFile *>(data));
-    _syscall(munmap(file->data_, file->size_));
-}
-
-static void *CYPoolFile(CYPool &pool, const char *path, size_t *psize) {
-    int fd(_syscall_(open(path, O_RDONLY), 1, ENOENT));
-    if (fd == -1)
-        return NULL;
-
-    struct stat stat;
-    _syscall(fstat(fd, &stat));
-    size_t size(stat.st_size);
-
-    *psize = size;
-
-    void *base;
-    if (size == 0)
-        base = pool.strndup("", 0);
-    else {
-        _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
-
-        CYFile *file(new (pool) CYFile(base, size));
-        pool.atexit(&CYFileExit, file);
-    }
-
-    _syscall(close(fd));
-    return base;
-}
-
-static CYUTF8String CYPoolFileUTF8String(CYPool &pool, const char *path) {
-    CYUTF8String data;
-    data.data = reinterpret_cast<char *>(CYPoolFile(pool, path, &data.size));
-    return data;
-}
-
 static const char *CYPoolLibraryPath(CYPool &pool) {
     Dl_info addr;
     _assert(dladdr(reinterpret_cast<void *>(&CYPoolLibraryPath), &addr) != 0);
@@ -2040,6 +2069,10 @@ static const char *CYPoolLibraryPath(CYPool &pool) {
     _assert(slash != NULL);
     *slash = '\0';
 
+    slash = strrchr(lib, '/');
+    if (slash != NULL && strcmp(slash, "/.libs") == 0)
+        *slash = '\0';
+
     return lib;
 }
 
@@ -2103,7 +2136,7 @@ static JSValueRef require_callAsFunction(JSContextRef context, JSObjectRef objec
 
 static bool CYRunScript(JSGlobalContextRef context, const char *path) {
     CYPool pool;
-    CYUTF8String code(CYPoolFileUTF8String(pool, path));
+    CYUTF8String code(CYPoolFileUTF8String(pool, pool.strcat(CYPoolLibraryPath(pool), path, NULL)));
     if (code.data == NULL)
         return false;
 
@@ -2195,6 +2228,10 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
     JSObjectRef all(JSObjectMake(context, All_, NULL));
     CYSetProperty(context, cycript, CYJSString("all"), all);
 
+    JSObjectRef cache(JSObjectMake(context, NULL, NULL));
+    CYSetProperty(context, cy, CYJSString("cache"), cache);
+    CYSetPrototype(context, cache, all);
+
     JSObjectRef alls(_jsccall(JSObjectCallAsConstructor, context, Array, 0, NULL));
     CYSetProperty(context, cycript, CYJSString("alls"), alls);
 
@@ -2210,13 +2247,13 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
             next = JSObjectGetPrototype(context, curr);
         }
 
-        CYSetPrototype(context, last, all);
+        CYSetPrototype(context, last, cache);
     }
 
     JSObjectRef System(JSObjectMake(context, NULL, NULL));
     CYSetProperty(context, cy, CYJSString("System"), System);
 
-    CYSetProperty(context, all, CYJSString("require"), &require_callAsFunction, kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, global, CYJSString("require"), &require_callAsFunction, kJSPropertyAttributeDontEnum);
 
     CYSetProperty(context, global, CYJSString("system"), System);
     CYSetProperty(context, System, CYJSString("args"), CYJSNull(context));
@@ -2231,27 +2268,27 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
     }
 #endif
 
-    CYSetProperty(context, global, CYJSString("dlerror"), CYMakeFunctor(context, "dlerror", "*"), kJSPropertyAttributeDontEnum);
-    CYSetProperty(context, global, CYJSString("RTLD_DEFAULT"), CYCastJSValue(context, reinterpret_cast<intptr_t>(RTLD_DEFAULT)), kJSPropertyAttributeDontEnum);
-    CYSetProperty(context, global, CYJSString("dlsym"), CYMakeFunctor(context, "dlsym", "^v^v*"), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("dlerror"), CYMakeFunctor(context, "dlerror", "*"), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("RTLD_DEFAULT"), CYCastJSValue(context, reinterpret_cast<intptr_t>(RTLD_DEFAULT)), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("dlsym"), CYMakeFunctor(context, "dlsym", "^v^v*"), kJSPropertyAttributeDontEnum);
 
-    CYSetProperty(context, global, CYJSString("NULL"), CYJSNull(context), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("NULL"), CYJSNull(context), kJSPropertyAttributeDontEnum);
 
-    CYSetProperty(context, global, CYJSString("bool"), CYMakeType(context, "B"), kJSPropertyAttributeDontEnum);
-    CYSetProperty(context, global, CYJSString("char"), CYMakeType(context, "c"), kJSPropertyAttributeDontEnum);
-    CYSetProperty(context, global, CYJSString("short"), CYMakeType(context, "s"), kJSPropertyAttributeDontEnum);
-    CYSetProperty(context, global, CYJSString("int"), CYMakeType(context, "i"), kJSPropertyAttributeDontEnum);
-    CYSetProperty(context, global, CYJSString("long"), CYMakeType(context, "l"), kJSPropertyAttributeDontEnum);
-    CYSetProperty(context, global, CYJSString("float"), CYMakeType(context, "f"), kJSPropertyAttributeDontEnum);
-    CYSetProperty(context, global, CYJSString("double"), CYMakeType(context, "d"), kJSPropertyAttributeDontEnum);
-
-    CYRunScript(context, "libcycript.cy");
+    CYSetProperty(context, cache, CYJSString("bool"), CYMakeType(context, "B"), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("char"), CYMakeType(context, "c"), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("short"), CYMakeType(context, "s"), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("int"), CYMakeType(context, "i"), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("long"), CYMakeType(context, "l"), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("float"), CYMakeType(context, "f"), kJSPropertyAttributeDontEnum);
+    CYSetProperty(context, cache, CYJSString("double"), CYMakeType(context, "d"), kJSPropertyAttributeDontEnum);
 
     for (CYHook *hook : GetHooks())
         if (hook->SetupContext != NULL)
             (*hook->SetupContext)(context);
 
     CYArrayPush(context, alls, cycript);
+
+    CYRunScript(context, "/libcycript.cy");
 }
 
 static JSGlobalContextRef context_;