diff --git a/ChangeLog b/ChangeLog index c699a8c24c..728bb30d13 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,7 @@ Graphics: Graphics.stringMetrics now returns 'unrenderableChars/imageCount/maxImageHeight' for much more info about rendering strings Graphics: wrapString now also wraps on slashes (to allow wrapping of URLs) nRF5x: when connecting to other devices, allow a slave latency of 2 (might increase reliability) + Fix `Got [ERASED] expecting X` when storage compacts while executing a function *in* storage on non-Bangle devices (fix #2431) 2v19 : Fix Object.values/entries for numeric keys after 2v18 regression (fix #2375) nRF52: for SD>5 use static buffers for advertising and scan response data (#2367) diff --git a/src/jsparse.c b/src/jsparse.c index 659c440d5c..d03523bb16 100644 --- a/src/jsparse.c +++ b/src/jsparse.c @@ -406,7 +406,7 @@ NO_INLINE bool jspeFunctionDefinitionInternal(JsVar *funcVar, bool expressionOnl if (!expressionOnly) { int brackets = 0; JsExecFlags oldExec = execInfo.execute; - execInfo.execute = EXEC_NO; // set no execute so we don't parse strings + execInfo.execute = EXEC_NO; // set no execute so we don't parse strings while (lex->tk && (brackets || lex->tk != '}')) { if (lex->tk == '{') brackets++; if (lex->tk == '}') brackets--; @@ -932,6 +932,11 @@ NO_INLINE JsVar *jspeFunctionCall(JsVar *function, JsVar *functionName, JsVar *t } jsvUnLock(thisVar); + /* It's possible that this call or a subcall may have compacted the filesystem + which changed the address the var in the iterator pointed to. If so we need to + copy it again. This should be quick-ish so lets' just do it rather than checking + whether we have compacted or not. https://github.com/espruino/Espruino/issues/2431 */ + if (lex) jsvStringIteratorUpdatePtr(&lex->it); return returnVar; } else if (isParsing) { // ---------------------------------- function, but not executing - just parse args and be done diff --git a/src/jsvariterator.c b/src/jsvariterator.c index 767fed71bb..bc50447fe5 100644 --- a/src/jsvariterator.c +++ b/src/jsvariterator.c @@ -265,20 +265,16 @@ void jsvStringIteratorNew(JsvStringIterator *it, JsVar *str, size_t startIdx) { it->var = jsvLockAgain(str); it->varIndex = 0; it->charsInVar = jsvGetCharactersInVar(it->var); - - if (jsvIsFlatString(it->var)) { - it->ptr = jsvGetFlatStringPointer(it->var); - } else if (jsvIsNativeString(it->var)) { - it->ptr = (char*)it->var->varData.nativeStr.ptr; #ifdef SPIFLASH_BASE - } else if (jsvIsFlashString(it->var)) { + if (jsvIsFlashString(it->var)) { + /* We need to handle flash strings separately as we want + to preload a buffer of data */ it->charsInVar = 0; it->charIdx = startIdx; // if it's not UTF8 we can just load up the bit we want immediately return jsvStringIteratorLoadFlashString(it); -#endif - } else{ - it->ptr = &it->var->varData.str[0]; } +#endif + jsvStringIteratorUpdatePtr(it); it->charIdx = startIdx; jsvStringIteratorCatchUp(it); } @@ -300,6 +296,22 @@ void jsvStringIteratorNewUTF8(JsvStringIterator *it, JsVar *str, size_t startIdx #endif } +/// Update the pointer on a String iterator (should not normally be needed except when allocating a new iterator, but we may call it if we think the pointer in the var may have changed, eg during compaction) +void jsvStringIteratorUpdatePtr(JsvStringIterator *it) { + if (jsvIsFlatString(it->var)) { + it->ptr = jsvGetFlatStringPointer(it->var); + } else if (jsvIsNativeString(it->var)) { + it->ptr = (char*)it->var->varData.nativeStr.ptr; +#ifdef SPIFLASH_BASE + } else if (jsvIsFlashString(it->var)) { + /* don't do anything for flash strings - they are + handled specially in jsvStringIteratorNew */ +#endif + } else if (it->var) + it->ptr = &it->var->varData.str[0]; + else + it->ptr = 0; +} void jsvStringIteratorClone(JsvStringIterator *dstit, JsvStringIterator *it) { *dstit = *it; diff --git a/src/jsvariterator.h b/src/jsvariterator.h index 3094499917..eda049b8e7 100644 --- a/src/jsvariterator.h +++ b/src/jsvariterator.h @@ -80,6 +80,9 @@ void jsvStringIteratorNew(JsvStringIterator *it, JsVar *str, size_t startIdx); /// Create a new String iterator from a string, starting from a specific character (ensures start character matches with actual UTF8 char number) void jsvStringIteratorNewUTF8(JsvStringIterator *it, JsVar *str, size_t startIdx); +/// Update the pointer on a String iterator (should not normally be needed except when allocating a new iterator, but we may call it if we think the pointer in the var may have changed, eg during compaction) +void jsvStringIteratorUpdatePtr(JsvStringIterator *it); + /// Clone the string iterator void jsvStringIteratorClone(JsvStringIterator *dstit, JsvStringIterator *it);