From fa7476a1ee3cd8907928809f8af44285d685c830 Mon Sep 17 00:00:00 2001 From: Konstantin Makarchev Date: Thu, 27 May 2021 23:39:49 +0300 Subject: [PATCH 1/2] fixed #10751, Base64, exclude last 3 bytes from bswap(for correct memory access), and process them manually --- src/base64.cr | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/base64.cr b/src/base64.cr index 9f05145d6f22..19d6fbc689eb 100644 --- a/src/base64.cr +++ b/src/base64.cr @@ -203,7 +203,8 @@ module Base64 bytes = chars.to_unsafe size = data.size cstr = data.to_unsafe - endcstr = cstr + size - size % 3 + endcstr = cstr + size - size % 3 - 3 + while cstr < endcstr n = Intrinsics.bswap32(cstr.as(UInt32*).value) yield bytes[(n >> 26) & 63] @@ -213,6 +214,20 @@ module Base64 cstr += 3 end + if size >= 3 + a = cstr.value + b = (cstr + 1).value + c = (cstr + 2).value + n = (a.to_u32 << 0x10) + (b.to_u32 << 0x08) + c + + yield bytes[(n >> 18) & 63] + yield bytes[(n >> 12) & 63] + yield bytes[(n >> 6) & 63] + yield bytes[(n) & 63] + + cstr += 3 + end + pd = size % 3 if pd == 1 n = (cstr.value.to_u32 << 16) From f2fddc60d711e6f13fc77109455978fd737f8761 Mon Sep 17 00:00:00 2001 From: Konstantin Makarchev Date: Fri, 28 May 2021 13:28:50 +0300 Subject: [PATCH 2/2] add comment --- src/base64.cr | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/base64.cr b/src/base64.cr index 19d6fbc689eb..36bb482d5634 100644 --- a/src/base64.cr +++ b/src/base64.cr @@ -205,6 +205,7 @@ module Base64 cstr = data.to_unsafe endcstr = cstr + size - size % 3 - 3 + # process bunch of full triples while cstr < endcstr n = Intrinsics.bswap32(cstr.as(UInt32*).value) yield bytes[(n >> 26) & 63] @@ -214,20 +215,17 @@ module Base64 cstr += 3 end + # process last full triple manually, because reading UInt32 not correct for guarded memory if size >= 3 - a = cstr.value - b = (cstr + 1).value - c = (cstr + 2).value - n = (a.to_u32 << 0x10) + (b.to_u32 << 0x08) + c - + n = (cstr.value.to_u32 << 16) | ((cstr + 1).value.to_u32 << 8) | (cstr + 2).value yield bytes[(n >> 18) & 63] yield bytes[(n >> 12) & 63] yield bytes[(n >> 6) & 63] yield bytes[(n) & 63] - cstr += 3 end + # process last partial triple pd = size % 3 if pd == 1 n = (cstr.value.to_u32 << 16)