diff --git a/ChangeLog b/ChangeLog index 4ccc86792..13faf3249 100644 --- a/ChangeLog +++ b/ChangeLog @@ -49,6 +49,8 @@ ESP32C3: don't kick connected BLE devices off if reset() is called ESP32C3: disable warnings about "BT_BTM: BTM_GetSecurityFlags false" Handle semicolons between field declarations in classes + Ensure that pretokenised Strings are loaded as Flat Strings when executed from a String in RAM + E.nativeCall also checks to see if getting data as a flat string failed (could have caused segfault) 2v24 : Bangle.js2: Add 'Bangle.touchRd()', 'Bangle.touchWr()' Bangle.js2: After Bangle.showTestScreen, put Bangle.js into a hard off state (not soft off) diff --git a/src/jsvar.c b/src/jsvar.c index d1b8ac458..22c995ba3 100644 --- a/src/jsvar.c +++ b/src/jsvar.c @@ -1632,21 +1632,9 @@ JsVar *jsvAsStringAndUnLock(JsVar *var) { JsVar *jsvAsFlatString(JsVar *var) { if (jsvIsFlatString(var)) return jsvLockAgain(var); JsVar *str = jsvAsString(var); - size_t len = jsvGetStringLength(str); - JsVar *flat = jsvNewFlatStringOfLength((unsigned int)len); - if (flat) { - JsvStringIterator src; - JsvStringIterator dst; - jsvStringIteratorNew(&src, str, 0); - jsvStringIteratorNew(&dst, flat, 0); - while (len--) { - jsvStringIteratorSetCharAndNext(&dst, jsvStringIteratorGetCharAndNext(&src)); - } - jsvStringIteratorFree(&src); - jsvStringIteratorFree(&dst); - } + JsVar *fs = jsvNewFlatStringFromStringVar(str, 0, JSVAPPENDSTRINGVAR_MAXLENGTH); jsvUnLock(str); - return flat; + return fs; } /** Given a JsVar meant to be an index to an array, convert it to @@ -1943,7 +1931,29 @@ void jsvAppendStringVar(JsVar *var, const JsVar *str, size_t stridx, size_t maxL jsvStringIteratorFree(&dst); } -/** Create a new String from a substring in RAM. It is always writable. jsvNewFromStringVar can reference a non-writable string. +/** Create a new flat string from the given var with the given index and length */ +JsVar *jsvNewFlatStringFromStringVar(JsVar *var, size_t stridx, size_t maxLength) { + assert(jsvIsString(var)); + size_t len = jsvGetStringLength(var); + if (stridx>len) len=0; + else len -= stridx; + if (len > maxLength) len = maxLength; + JsVar *flat = jsvNewFlatStringOfLength((unsigned int)len); + if (flat) { + JsvStringIterator src; + JsvStringIterator dst; + jsvStringIteratorNew(&src, var, stridx); + jsvStringIteratorNew(&dst, flat, 0); + while (len--) { + jsvStringIteratorSetCharAndNext(&dst, jsvStringIteratorGetCharAndNext(&src)); + } + jsvStringIteratorFree(&src); + jsvStringIteratorFree(&dst); + } + return flat; +} + +/** Create a new (non-flat) String from a substring in RAM. It is always writable and appendable. jsvNewFromStringVar can reference a non-writable string. The Argument must be a string. stridx = start char or str, maxLength = max number of characters (can be JSVAPPENDSTRINGVAR_MAXLENGTH) */ JsVar *jsvNewWritableStringFromStringVar(const JsVar *str, size_t stridx, size_t maxLength) { JsVar *var = jsvNewFromEmptyString(); @@ -1958,6 +1968,7 @@ JsVar *jsvNewWritableStringFromStringVar(const JsVar *str, size_t stridx, size_t /** Create a new variable from a substring. If a Native or Flash String, the memory area will be referenced (so the new string may not be writable) The Argument must be a string. stridx = start char or str, maxLength = max number of characters (can be JSVAPPENDSTRINGVAR_MAXLENGTH) */ JsVar *jsvNewFromStringVar(const JsVar *str, size_t stridx, size_t maxLength) { + assert(jsvIsString(str)); if (jsvIsNativeString(str) || jsvIsFlashString(str)) { // if it's a flash string, just change the pointer (but we must check length) size_t l = jsvGetStringLength(str); @@ -1968,6 +1979,18 @@ JsVar *jsvNewFromStringVar(const JsVar *str, size_t stridx, size_t maxLength) { res->varData.nativeStr.len = (JsVarDataNativeStrLength)maxLength; return res; } + if (jsvIsFlatString(str)) { + // work out how long we really want it... + size_t length = jsvGetCharactersInVar(str); + if (stridx >= length) length = 0; + else length -= stridx; + if (length > maxLength) length = maxLength; + // if it's long enough to make sense, create a flat string instead + if (length > JSV_FLAT_STRING_BREAK_EVEN) { + JsVar *var = jsvNewFlatStringFromStringVar(str, stridx, length); + if (var) return var; + } + } return jsvNewWritableStringFromStringVar(str, stridx, maxLength); } diff --git a/src/jsvar.h b/src/jsvar.h index 86d3a635f..6d802393f 100644 --- a/src/jsvar.h +++ b/src/jsvar.h @@ -318,7 +318,9 @@ JsVar *jsvNewUTF8String(JsVar* dataString); ///< Create a new unicode string usi JsVar *jsvNewUTF8StringAndUnLock(JsVar* dataString); ///< Create a new unicode string using the given data string for backing #endif static ALWAYS_INLINE JsVar *jsvNewNull() { return jsvNewWithFlags(JSV_NULL); } ;///< Create a new null variable -/** Create a new String from a substring in RAM. It is always writable. jsvNewFromStringVar can reference a non-writable string. +/** Create a new flat string from the given var with the given index and length */ +JsVar *jsvNewFlatStringFromStringVar(JsVar *var, size_t stridx, size_t maxLength); +/** Create a new (non-flat) String from a substring in RAM. It is always writable and appendable. jsvNewFromStringVar can reference a non-writable string. The Argument must be a string. stridx = start char or str, maxLength = max number of characters (can be JSVAPPENDSTRINGVAR_MAXLENGTH) */ JsVar *jsvNewWritableStringFromStringVar(const JsVar *str, size_t stridx, size_t maxLength); /** Create a new variable from a substring. If a Native or Flash String, the memory area will be referenced (so the new string may not be writable) diff --git a/src/jswrap_espruino.c b/src/jswrap_espruino.c index d4f1f0a8e..bace3f856 100644 --- a/src/jswrap_espruino.c +++ b/src/jswrap_espruino.c @@ -281,6 +281,10 @@ JsVar *jswrap_espruino_nativeCall(JsVarInt addr, JsVar *signature, JsVar *data) JsVar *fn = jsvNewNativeFunction((void *)(size_t)addr, (unsigned short)argTypes); if (data) { JsVar *flat = jsvAsFlatString(data); + if (!flat) { // can't get a flat string! + jsvUnLock(fn); + return 0; + } jsvAddNamedChildAndUnLock(fn, flat, JSPARSE_FUNCTION_CODE_NAME); } return fn;