From 53e8bd659a1b1cba763ec7e6fe9882d203b64375 Mon Sep 17 00:00:00 2001 From: Sei Lisa Date: Sun, 21 Mar 2021 19:05:37 +0100 Subject: [PATCH] The Base64 functions that used to produce garbage no longer do --- lslopt/lslbasefuncs.py | 38 +++++++------------ unit_tests/regression.suite/fixed-b64.lsl | 13 +++++++ unit_tests/regression.suite/fixed-b64.out | 7 ++++ unit_tests/regression.suite/fixed-b64.run | 1 + .../regression.suite/non-computable.lsl | 3 -- .../regression.suite/non-computable.out | 3 -- 6 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 unit_tests/regression.suite/fixed-b64.lsl create mode 100644 unit_tests/regression.suite/fixed-b64.out create mode 100644 unit_tests/regression.suite/fixed-b64.run diff --git a/lslopt/lslbasefuncs.py b/lslopt/lslbasefuncs.py index 51051fb..4f38519 100644 --- a/lslopt/lslbasefuncs.py +++ b/lslopt/lslbasefuncs.py @@ -28,8 +28,9 @@ # # In some instances, the result can't be computed; in these cases the function # raises a LSLCantCompute exception that is caught by the optimizer to leave -# the expression unchanged. For example, llBase64ToInteger("AA") returns -# unpredictable garbage in the low bytes in LSL, so it is left unchanged. +# the expression unchanged. For example, llXorBase64Strings has a delay, so it +# can't just be replaced by its value; llFrand produces unpredictable results +# (by design) in most cases, but not all. # # The JSON functions have been separated to their own module. @@ -993,8 +994,6 @@ def llAxisAngle2Rot(axis, angle): s = math.sin(angle*0.5) return Quaternion(F32((axis[0]*s, axis[1]*s, axis[2]*s, c))) -# NOTE: This one does not always return the same value in LSL. When it isn't -# deterministic, it raises ELSLCantCompute. def llBase64ToInteger(s): s = fs(s) if len(s) > 8: @@ -1002,14 +1001,11 @@ def llBase64ToInteger(s): s = b64_re.search(s).group() i = len(s) s = b64decode(s + u'='*(-i & 3)) - if len(s) < 3: - # not computable deterministically - raise ELSLCantCompute - s = bytearray(s + b'\0')[:4] + s = bytearray(s + b'\0\0\0\0')[:4] i = s[0] if s[0] < 128 else s[0]-256 return (i<<24)+(s[1]<<16)+(s[2]<<8)+s[3] -b64tos_re = re.compile( +b64tostr_re = re.compile( b'(' # Those pass through and are caught by InternalUTF8toString: b'\x00$' # NUL at last position (zstr removes it) @@ -1052,9 +1048,9 @@ def llBase64ToString(s): byteseq = bytearray(b64decode(s + u'=' * (-len(s) & 3))) pos = 0 - match = b64tos_re.search(byteseq, pos) + match = b64tostr_re.search(byteseq, pos) while match is not None: - assert match.group(3) is None, 'Fail in b64tos_re: ' + match.group(3) + assert match.group(3) is None, 'Fail in b64tostr_re: ' + match.group(3) L = len(match.group(2) or '') if L: byteseq[pos:pos+L] = b'?' @@ -1062,7 +1058,7 @@ def llBase64ToString(s): else: pos = match.end(1) - match = b64tos_re.search(byteseq, pos) + match = b64tostr_re.search(byteseq, pos) return InternalUTF8toString(byteseq) @@ -1917,10 +1913,6 @@ def llXorBase64(s, xor): if L2 == 0: # The input xor string starts with zero or one valid Base64 characters. - # This produces garbage bytes (the first byte is zero though). - if L1 > 2: - # We don't produce a result in this case. - raise ELSLCantCompute L2 = 2 xor = u'AA' @@ -1932,10 +1924,12 @@ def llXorBase64(s, xor): ret = bytearray(b'') Bug3763 = 3763 in Bugs - # BUG-3763 consists of the binary string having an extra NULL every time after the second repetition of - # the XOR pattern. For example, if the XOR binary string is b'pqr' and the input string is - # b'12345678901234567890', the XOR binary string behaves as if it was b'pqrpqr\0pqr\0pqr\0pqr\0pq'. - # We emulate that by adding the zero and increasing the length the first time. + # BUG-3763 consists of the binary string having an extra NULL every time + # after the second repetition of the XOR pattern. For example, if the XOR + # binary string is b'pqr' and the input string is b'12345678901234567890', + # the XOR binary string behaves as if it was b'pqrpqr\0pqr\0pqr\0pqr\0pq'. + # We emulate that by adding the zero and increasing the length the first + # time. for c in s: ret.append(c ^ xor[i]) i += 1 @@ -2007,10 +2001,6 @@ def llXorBase64StringsCorrect(s, xor): if L2 == 0: # The input xor string starts with zero or one valid Base64 characters. - # This produces garbage bytes (the first byte is zero though). - if L1 > 2: - # We don't produce a result in this case. - raise ELSLCantCompute L2 = 2 xor = u'AA' diff --git a/unit_tests/regression.suite/fixed-b64.lsl b/unit_tests/regression.suite/fixed-b64.lsl new file mode 100644 index 0000000..7fb22b4 --- /dev/null +++ b/unit_tests/regression.suite/fixed-b64.lsl @@ -0,0 +1,13 @@ +// Some Base64 functions used to return garbage, now they no longer do +default +{ + timer() + { + llSetPrimitiveParams( // we need a function that causes side effects, + // so that it isn't optimized out + [ llXorBase64StringsCorrect("++++", "?") + , llXorBase64("++++", "?") + , llBase64ToInteger("ABC") + ]); + } +} diff --git a/unit_tests/regression.suite/fixed-b64.out b/unit_tests/regression.suite/fixed-b64.out new file mode 100644 index 0000000..077507f --- /dev/null +++ b/unit_tests/regression.suite/fixed-b64.out @@ -0,0 +1,7 @@ +default +{ + timer() + { + llSetPrimitiveParams((list)"++++" + "++++" + 1048576); + } +} diff --git a/unit_tests/regression.suite/fixed-b64.run b/unit_tests/regression.suite/fixed-b64.run new file mode 100644 index 0000000..c83b20c --- /dev/null +++ b/unit_tests/regression.suite/fixed-b64.run @@ -0,0 +1 @@ +main.py -y -O -dcr,-optfloats - diff --git a/unit_tests/regression.suite/non-computable.lsl b/unit_tests/regression.suite/non-computable.lsl index efd128e..cef64ee 100644 --- a/unit_tests/regression.suite/non-computable.lsl +++ b/unit_tests/regression.suite/non-computable.lsl @@ -22,9 +22,6 @@ default , llGetDisplayName(TEXTURE_BLANK) , llGetEnv("estate_name") , llXorBase64Strings("++++", "?") - , llXorBase64StringsCorrect("++++", "?") - , llXorBase64("++++", "?") - , llBase64ToInteger("ABC") , llAbs(-2147483648) ]); } diff --git a/unit_tests/regression.suite/non-computable.out b/unit_tests/regression.suite/non-computable.out index a4326f8..480e701 100644 --- a/unit_tests/regression.suite/non-computable.out +++ b/unit_tests/regression.suite/non-computable.out @@ -20,9 +20,6 @@ default , llGetDisplayName("5748decc-f629-461c-9a36-a35a221fe21f") , llGetEnv("estate_name") , llXorBase64Strings("++++", "?") - , llXorBase64StringsCorrect("++++", "?") - , llXorBase64("++++", "?") - , llBase64ToInteger("ABC") , llAbs(((integer)-2147483648)) ]); }