From 81535499d641905d8d18ab0a9a3c88e134d2b1d2 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 14 Aug 2018 13:24:10 +0300 Subject: [PATCH 1/5] [21476] Ensure "the extents of tArray" returns empty when keys are not integers --- docs/notes/bugfix-21476.md | 1 + engine/src/exec-array.cpp | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 docs/notes/bugfix-21476.md diff --git a/docs/notes/bugfix-21476.md b/docs/notes/bugfix-21476.md new file mode 100644 index 00000000000..89bcac7782c --- /dev/null +++ b/docs/notes/bugfix-21476.md @@ -0,0 +1 @@ +# Ensure "the extents of tArray" returns empty if the keys of tArray are not integers diff --git a/engine/src/exec-array.cpp b/engine/src/exec-array.cpp index d286dfbff3e..41d8790f264 100644 --- a/engine/src/exec-array.cpp +++ b/engine/src/exec-array.cpp @@ -978,6 +978,12 @@ bool MCArraysSplitIndexes(MCNameRef p_key, integer_t*& r_indexes, uindex_t& r_co r_all_integers = false; break; } + + if (!MCNumberIsInteger(*t_number)) + { + r_all_integers = false; + break; + } if (!t_indexes . Push(MCNumberFetchAsInteger(*t_number))) return false; From dde0dcc00d70153788b749b1894d961c017de718 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Tue, 14 Aug 2018 16:28:39 +0300 Subject: [PATCH 2/5] [21476] Ensure integer checks are stricter --- engine/src/exec-array.cpp | 9 +- engine/src/exec-filters.cpp | 2 +- libfoundation/include/foundation.h | 3 +- libfoundation/src/foundation-number.cpp | 215 ++++++++++++++---------- 4 files changed, 130 insertions(+), 99 deletions(-) diff --git a/engine/src/exec-array.cpp b/engine/src/exec-array.cpp index 41d8790f264..c9aac46bd9d 100644 --- a/engine/src/exec-array.cpp +++ b/engine/src/exec-array.cpp @@ -970,7 +970,8 @@ bool MCArraysSplitIndexes(MCNameRef p_key, integer_t*& r_indexes, uindex_t& r_co return false; MCAutoNumberRef t_number; - if (!MCNumberParse(*t_substring, &t_number)) + + if (!MCNumberParseInteger(*t_substring, &t_number)) { if (!t_indexes . Push(0)) return false; @@ -979,12 +980,6 @@ bool MCArraysSplitIndexes(MCNameRef p_key, integer_t*& r_indexes, uindex_t& r_co break; } - if (!MCNumberIsInteger(*t_number)) - { - r_all_integers = false; - break; - } - if (!t_indexes . Push(MCNumberFetchAsInteger(*t_number))) return false; diff --git a/engine/src/exec-filters.cpp b/engine/src/exec-filters.cpp index 25717ee9f53..dce97c110f8 100644 --- a/engine/src/exec-filters.cpp +++ b/engine/src/exec-filters.cpp @@ -335,7 +335,7 @@ static bool MCU_gettemplate(MCStringRef format, uindex_t &x_offset, unichar_t &c while (isdigit(MCStringGetCharAtIndex(format, x_offset + t_number_size))) t_number_size++; - if (MCNumberParseOffset(format, x_offset, t_number_size, &t_number)) + if (MCNumberParseOffset(format, x_offset, t_number_size, false, &t_number)) { count = MCNumberFetchAsUnsignedInteger(*t_number); x_offset += t_number_size; diff --git a/libfoundation/include/foundation.h b/libfoundation/include/foundation.h index c1a8e7f1219..be7d2ac93e8 100755 --- a/libfoundation/include/foundation.h +++ b/libfoundation/include/foundation.h @@ -2051,8 +2051,9 @@ MC_DLLEXPORT real64_t MCNumberFetchAsReal(MCNumberRef number); MC_DLLEXPORT bool MCNumberParseOffsetPartial(MCStringRef p_string, uindex_t offset, uindex_t &r_chars_used, MCNumberRef &r_number); -MC_DLLEXPORT bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, MCNumberRef &r_number); +MC_DLLEXPORT bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, bool p_integer_only, MCNumberRef &r_number); MC_DLLEXPORT bool MCNumberParse(MCStringRef string, MCNumberRef& r_number); +MC_DLLEXPORT bool MCNumberParseInteger(MCStringRef string, MCNumberRef& r_number); MC_DLLEXPORT bool MCNumberParseUnicodeChars(const unichar_t *chars, uindex_t char_count, MCNumberRef& r_number); #if defined(__HAS_CORE_FOUNDATION__) diff --git a/libfoundation/src/foundation-number.cpp b/libfoundation/src/foundation-number.cpp index 65ceb1b8d39..b10a6318f0a 100644 --- a/libfoundation/src/foundation-number.cpp +++ b/libfoundation/src/foundation-number.cpp @@ -23,6 +23,14 @@ along with LiveCode. If not see . */ //////////////////////////////////////////////////////////////////////////////// +// Forward declarations of internal utility functions + +static bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p_full_string, bool p_integer_only, uindex_t &r_length_used, MCNumberRef &r_number); +static bool __MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, bool p_integer_only, MCNumberRef &r_number); +static bool __MCNumberParseUnicodeChars(const unichar_t *p_chars, uindex_t p_char_count, bool p_integer_only, MCNumberRef& r_number); + +//////////////////////////////////////////////////////////////////////////////// + MC_DLLEXPORT_DEF bool MCNumberCreateWithInteger(integer_t p_value, MCNumberRef& r_number) { @@ -126,31 +134,101 @@ compare_t MCNumberCompareTo(MCNumberRef self, MCNumberRef p_other_self) return 0; } -bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p_full_string, uindex_t &r_length_used, MCNumberRef &r_number) +///////////////////////////////////////////////////////////////////////////////// + +MC_DLLEXPORT_DEF +bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, bool p_integer_only, MCNumberRef &r_number) +{ + return __MCNumberParseOffset(p_string, offset, char_count, p_integer_only, r_number); +} + +MC_DLLEXPORT_DEF +bool MCNumberParse(MCStringRef p_string, MCNumberRef &r_number) +{ + return MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), false, r_number); +} + +MC_DLLEXPORT_DEF +bool MCNumberParseInteger(MCStringRef p_string, MCNumberRef &r_number) +{ + return MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), true, r_number); +} + +MC_DLLEXPORT_DEF +bool MCNumberParseUnicodeChars(const unichar_t *p_chars, uindex_t p_char_count, MCNumberRef& r_number) +{ + return __MCNumberParseUnicodeChars(p_chars, p_char_count, false, r_number); +} + +MC_DLLEXPORT_DEF +bool MCNumberParseOffsetPartial(MCStringRef p_string, uindex_t offset, uindex_t &r_chars_used, MCNumberRef &r_number) { bool t_success; t_success = true; - MCNumberRef t_number; - t_number = nil; + char *t_buffer; + t_buffer = nil; + + const char *t_native_string; + t_native_string = nil; + + uindex_t t_length; + t_length = MCStringGetLength(p_string); + + if (offset > t_length) + offset = t_length; + + if (MCStringIsNative(p_string)) + t_native_string = (const char*)MCStringGetNativeCharPtr(p_string) + offset; + else + { + t_success = MCMemoryNewArray(t_length - offset + 1, t_buffer); + + uindex_t t_native_char_count; + if (t_success) + t_success = MCUnicodeCharsMapToNative(MCStringGetCharPtr(p_string) + offset, t_length - offset, (char_t*)t_buffer, t_native_char_count, '?'); + + t_native_string = t_buffer; + } + + if (t_success) + t_success = __MCNumberParseNativeString(t_native_string, t_length - offset, false, false, r_chars_used, r_number); + + MCMemoryDeleteArray(t_buffer); + return t_success; +} + +//////////////////////////////////////////////////////////////////////////////// + +static bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p_full_string, bool p_integer_only, uindex_t &r_length_used, MCNumberRef &r_number) +{ + bool t_success; + t_success = true; + + MCNumberRef t_number; + t_number = nil; + uinteger_t t_base; t_base = 10; const char *t_string; t_string = p_string; - if (p_length > 2 && - p_string[0] == '0' && - (p_string[1] == 'x' || p_string[1] == 'X')) - { - // If the string begins with 0x then parse as hex, and discard first two chars - t_base = 16; - t_string += 2; + if (!p_integer_only) + { + if (p_length > 2 && + p_string[0] == '0' && + (p_string[1] == 'x' || p_string[1] == 'X')) + { + // If the string begins with 0x then parse as hex, and discard first two chars + t_base = 16; + t_string += 2; + } } errno = 0; - + char *t_end; t_end = nil; @@ -166,13 +244,17 @@ bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p #endif t_success = (errno != ERANGE) && (p_full_string ? (t_end - p_string == (ptrdiff_t)p_length) : (t_end != t_string)); + + if (!t_success && p_integer_only) + return false; + if (t_success) t_success = MCNumberCreateWithInteger(t_integer, t_number); // If parsing as base 10 unsigned integer failed, try to parse as real. else if (t_base == 10) { errno = 0; - + real64_t t_real; t_real = strtod(p_string, &t_end); @@ -181,18 +263,17 @@ bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p if (t_success) t_success = MCNumberCreateWithReal(t_real, t_number); } - - if (t_success) - { - r_number = t_number; - r_length_used = t_end - p_string; - } - - return t_success; + + if (t_success) + { + r_number = t_number; + r_length_used = t_end - p_string; + } + + return t_success; } -MC_DLLEXPORT_DEF -bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, MCNumberRef &r_number) +static bool __MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, bool p_integer_only, MCNumberRef &r_number) { uindex_t length = MCStringGetLength(p_string); if (offset > length) @@ -207,83 +288,37 @@ bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_co bool t_success; t_success = false; - uindex_t t_length_used; - t_length_used = 0; - - t_success = __MCNumberParseNativeString((const char*)MCStringGetNativeCharPtr(p_string) + offset, char_count, true, t_length_used, r_number); - - return t_success; -} - -MC_DLLEXPORT_DEF -bool MCNumberParse(MCStringRef p_string, MCNumberRef &r_number) -{ - return MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), r_number); + uindex_t t_length_used; + t_length_used = 0; + + t_success = __MCNumberParseNativeString((const char*)MCStringGetNativeCharPtr(p_string) + offset, char_count, true, p_integer_only, t_length_used, r_number); + + return t_success; } -MC_DLLEXPORT_DEF -bool MCNumberParseUnicodeChars(const unichar_t *p_chars, uindex_t p_char_count, MCNumberRef& r_number) +static bool __MCNumberParseUnicodeChars(const unichar_t *p_chars, uindex_t p_char_count, bool p_integer_only, MCNumberRef& r_number) { - char *t_native_chars; - if (!MCMemoryNewArray(p_char_count + 1, t_native_chars)) - return false; + char *t_native_chars; + if (!MCMemoryNewArray(p_char_count + 1, t_native_chars)) + return false; - uindex_t t_native_char_count; - MCUnicodeCharsMapToNative(p_chars, p_char_count, (char_t *)t_native_chars, t_native_char_count, '?'); + uindex_t t_native_char_count; + MCUnicodeCharsMapToNative(p_chars, p_char_count, (char_t *)t_native_chars, t_native_char_count, '?'); - bool t_success; - t_success = false; - - uindex_t t_length_used; - t_length_used = 0; - - t_success = __MCNumberParseNativeString(t_native_chars, p_char_count, true, t_length_used, r_number); + bool t_success; + t_success = false; - MCMemoryDeleteArray(t_native_chars); + uindex_t t_length_used; + t_length_used = 0; - return t_success; -} - -MC_DLLEXPORT_DEF -bool MCNumberParseOffsetPartial(MCStringRef p_string, uindex_t offset, uindex_t &r_chars_used, MCNumberRef &r_number) -{ - bool t_success; - t_success = true; - - char *t_buffer; - t_buffer = nil; - - const char *t_native_string; - t_native_string = nil; - - uindex_t t_length; - t_length = MCStringGetLength(p_string); - - if (offset > t_length) - offset = t_length; - - if (MCStringIsNative(p_string)) - t_native_string = (const char*)MCStringGetNativeCharPtr(p_string) + offset; - else - { - t_success = MCMemoryNewArray(t_length - offset + 1, t_buffer); - - uindex_t t_native_char_count; - if (t_success) - t_success = MCUnicodeCharsMapToNative(MCStringGetCharPtr(p_string) + offset, t_length - offset, (char_t*)t_buffer, t_native_char_count, '?'); - - t_native_string = t_buffer; - } - - if (t_success) - t_success = __MCNumberParseNativeString(t_native_string, t_length - offset, false, r_chars_used, r_number); - - MCMemoryDeleteArray(t_buffer); - - return t_success; + t_success = __MCNumberParseNativeString(t_native_chars, p_char_count, true, p_integer_only, t_length_used, r_number); + + MCMemoryDeleteArray(t_native_chars); + + return t_success; } -//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////// bool __MCNumberCopyDescription(__MCNumber *self, MCStringRef& r_string) { From 6971f8d68fc9d69599ee8de71ecdb2d5d8dca7c6 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Wed, 15 Aug 2018 08:22:03 +0300 Subject: [PATCH 3/5] Added tests --- tests/lcs/core/array/array.livecodescript | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/lcs/core/array/array.livecodescript b/tests/lcs/core/array/array.livecodescript index 9721efab32e..35768089ea2 100644 --- a/tests/lcs/core/array/array.livecodescript +++ b/tests/lcs/core/array/array.livecodescript @@ -113,6 +113,23 @@ on TestExtents TestAssert "Extents of dimensional arrays", the extents of tDimensionalArray is tExpectedExtents end TestExtents +on TestExtentsDecimal + local tArray + repeat with i=1 to 5 + put "true" into tArray[i] + end repeat + put "false" into tArray[1.0] + + TestAssert "Extents of array with a decimal key", the extents of tArray is empty + + delete variable tArray[1.0] + TestAssert "Extents of array without key", the extents of tArray is (item 1 of tSequenceKeys, item -1 of tSequenceKeys) + + put "false" into tArray[pi] + TestAssert "Extents of array with another decimal key", the extents of tArray is empty + +end TestExtentsDecimal + on __testIsAmong pUseIsAmong local tArray, tKeyList, tKeys From baa4384ad8b603ab1da77cd1013257a37c4c5423 Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Wed, 15 Aug 2018 09:41:59 +0300 Subject: [PATCH 4/5] Fixed test that failed --- tests/lcs/core/array/array.livecodescript | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/lcs/core/array/array.livecodescript b/tests/lcs/core/array/array.livecodescript index 35768089ea2..a597ba9de2a 100644 --- a/tests/lcs/core/array/array.livecodescript +++ b/tests/lcs/core/array/array.livecodescript @@ -123,7 +123,9 @@ on TestExtentsDecimal TestAssert "Extents of array with a decimal key", the extents of tArray is empty delete variable tArray[1.0] - TestAssert "Extents of array without key", the extents of tArray is (item 1 of tSequenceKeys, item -1 of tSequenceKeys) + local tSequenceKeys + put __keysForArray(kSequenceArray) into tSequenceKeys + TestAssert "Extents of array without a decimal key", the extents of tArray is (item 1 of tSequenceKeys, item -1 of tSequenceKeys) put "false" into tArray[pi] TestAssert "Extents of array with another decimal key", the extents of tArray is empty From 7254625bece2dd127bfa16d97a2bb7275a115efd Mon Sep 17 00:00:00 2001 From: livecodepanos Date: Wed, 15 Aug 2018 20:02:51 +0300 Subject: [PATCH 5/5] Removed flag from public function --- engine/src/exec-filters.cpp | 2 +- libfoundation/include/foundation.h | 2 +- libfoundation/src/foundation-number.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/engine/src/exec-filters.cpp b/engine/src/exec-filters.cpp index dce97c110f8..25717ee9f53 100644 --- a/engine/src/exec-filters.cpp +++ b/engine/src/exec-filters.cpp @@ -335,7 +335,7 @@ static bool MCU_gettemplate(MCStringRef format, uindex_t &x_offset, unichar_t &c while (isdigit(MCStringGetCharAtIndex(format, x_offset + t_number_size))) t_number_size++; - if (MCNumberParseOffset(format, x_offset, t_number_size, false, &t_number)) + if (MCNumberParseOffset(format, x_offset, t_number_size, &t_number)) { count = MCNumberFetchAsUnsignedInteger(*t_number); x_offset += t_number_size; diff --git a/libfoundation/include/foundation.h b/libfoundation/include/foundation.h index be7d2ac93e8..e7855a13f98 100755 --- a/libfoundation/include/foundation.h +++ b/libfoundation/include/foundation.h @@ -2051,7 +2051,7 @@ MC_DLLEXPORT real64_t MCNumberFetchAsReal(MCNumberRef number); MC_DLLEXPORT bool MCNumberParseOffsetPartial(MCStringRef p_string, uindex_t offset, uindex_t &r_chars_used, MCNumberRef &r_number); -MC_DLLEXPORT bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, bool p_integer_only, MCNumberRef &r_number); +MC_DLLEXPORT bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, MCNumberRef &r_number); MC_DLLEXPORT bool MCNumberParse(MCStringRef string, MCNumberRef& r_number); MC_DLLEXPORT bool MCNumberParseInteger(MCStringRef string, MCNumberRef& r_number); MC_DLLEXPORT bool MCNumberParseUnicodeChars(const unichar_t *chars, uindex_t char_count, MCNumberRef& r_number); diff --git a/libfoundation/src/foundation-number.cpp b/libfoundation/src/foundation-number.cpp index b10a6318f0a..671260ec8cf 100644 --- a/libfoundation/src/foundation-number.cpp +++ b/libfoundation/src/foundation-number.cpp @@ -137,21 +137,21 @@ compare_t MCNumberCompareTo(MCNumberRef self, MCNumberRef p_other_self) ///////////////////////////////////////////////////////////////////////////////// MC_DLLEXPORT_DEF -bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, bool p_integer_only, MCNumberRef &r_number) +bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, MCNumberRef &r_number) { - return __MCNumberParseOffset(p_string, offset, char_count, p_integer_only, r_number); + return __MCNumberParseOffset(p_string, offset, char_count, false, r_number); } MC_DLLEXPORT_DEF bool MCNumberParse(MCStringRef p_string, MCNumberRef &r_number) { - return MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), false, r_number); + return __MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), false, r_number); } MC_DLLEXPORT_DEF bool MCNumberParseInteger(MCStringRef p_string, MCNumberRef &r_number) { - return MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), true, r_number); + return __MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), true, r_number); } MC_DLLEXPORT_DEF