From a79a0084b6f213d66e33ab2d7572b257af1a9257 Mon Sep 17 00:00:00 2001 From: Matheus Marchini Date: Fri, 27 Sep 2019 16:52:28 -0700 Subject: [PATCH] src: fix String::Length for Node.js v12.3.0 Type of String::Length changed from SMI to int32. This commit changes String::Length to use the new type. String::Length now returns a CheckedType, and places calling String::Length will check the type using .Check instead of Error::Fail, making the code more resilient in case the String length can't be loaded properly. PR-URL: https://github.com/nodejs/llnode/pull/302 Reviewed-By: Colin Ihrig --- src/llv8-constants.cc | 5 +++++ src/llv8-constants.h | 1 + src/llv8-inl.h | 51 ++++++++++++++++++++++++++++++------------- src/llv8.cc | 14 ++++++++++++ src/llv8.h | 7 +++++- 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/llv8-constants.cc b/src/llv8-constants.cc index 3f2f83ff..124b6d50 100644 --- a/src/llv8-constants.cc +++ b/src/llv8-constants.cc @@ -299,7 +299,12 @@ void String::Load() { kExternalStringTag = LoadConstant("ExternalStringTag"); kThinStringTag = LoadConstant("ThinStringTag"); + kLengthIsSmi = true; kLengthOffset = LoadConstant("class_String__length__SMI"); + if (kLengthOffset == -1) { + kLengthIsSmi = false; + kLengthOffset = LoadConstant("class_String__length__int32_t"); + } } diff --git a/src/llv8-constants.h b/src/llv8-constants.h index a1e6dad3..52112b0b 100644 --- a/src/llv8-constants.h +++ b/src/llv8-constants.h @@ -266,6 +266,7 @@ class String : public Module { int64_t kThinStringTag; int64_t kLengthOffset; + bool kLengthIsSmi; protected: void Load(); diff --git a/src/llv8-inl.h b/src/llv8-inl.h index 038ef080..b792cb49 100644 --- a/src/llv8-inl.h +++ b/src/llv8-inl.h @@ -17,6 +17,12 @@ inline int32_t LLV8::LoadValue(int64_t addr, Error& err) { return LoadUnsigned(addr, 4, err); } +template <> +inline CheckedType LLV8::LoadValue>( + int64_t addr) { + return LoadUnsigned(addr, 4); +} + template inline T LLV8::LoadValue(int64_t addr, Error& err) { int64_t ptr; @@ -363,7 +369,23 @@ inline int64_t String::Encoding(Error& err) { return type & v8()->string()->kEncodingMask; } -ACCESSOR(String, Length, string()->kLengthOffset, Smi) +inline CheckedType String::Length(Error& err) { + RETURN_IF_INVALID((*this), CheckedType()); + + if (v8()->string()->kLengthIsSmi) { + Smi len = LoadFieldValue(v8()->string()->kLengthOffset, err); + RETURN_IF_INVALID(len, CheckedType()); + + return CheckedType(len.GetValue()); + } + + CheckedType len = v8()->LoadValue>( + LeaField(v8()->string()->kLengthOffset)); + RETURN_IF_INVALID(len, CheckedType()); + + return len; +} + ACCESSOR(Script, Name, script()->kNameOffset, String) ACCESSOR(Script, LineOffset, script()->kLineOffsetOffset, Smi) @@ -610,16 +632,16 @@ inline int64_t FixedTypedArrayBase::GetExternal(Error& err) { inline std::string OneByteString::ToString(Error& err) { int64_t chars = LeaField(v8()->one_byte_string()->kCharsOffset); - Smi len = Length(err); - if (err.Fail()) return std::string(); - return v8()->LoadString(chars, len.GetValue(), err); + CheckedType len = Length(err); + RETURN_IF_INVALID(len, std::string()); + return v8()->LoadString(chars, *len, err); } inline std::string TwoByteString::ToString(Error& err) { int64_t chars = LeaField(v8()->two_byte_string()->kCharsOffset); - Smi len = Length(err); - if (err.Fail()) return std::string(); - return v8()->LoadTwoByteString(chars, len.GetValue(), err); + CheckedType len = Length(err); + RETURN_IF_INVALID(len, std::string()); + return v8()->LoadTwoByteString(chars, *len, err); } inline std::string ConsString::ToString(Error& err) { @@ -653,24 +675,23 @@ inline std::string SlicedString::ToString(Error& err) { Smi offset = Offset(err); if (err.Fail()) return std::string(); - Smi length = Length(err); - if (err.Fail()) return std::string(); + CheckedType length = Length(err); + RETURN_IF_INVALID(length, std::string()); std::string tmp = parent.ToString(err); if (err.Fail()) return std::string(); int64_t off = offset.GetValue(); - int64_t len = length.GetValue(); int64_t tmp_size = tmp.size(); - if (off > tmp_size || len > tmp_size) { + if (off > tmp_size || *length > tmp_size) { err = Error::Failure("Failed to display sliced string 0x%016" PRIx64 - " (offset = 0x%016" PRIx64 ", length = 0x%016" PRIx64 - ") from parent string 0x%016" PRIx64 + " (offset = 0x%016" PRIx64 + ", length = %d) from parent string 0x%016" PRIx64 " (length = 0x%016" PRIx64 ")", - raw(), off, len, parent.raw(), tmp_size); + raw(), off, *length, parent.raw(), tmp_size); return std::string(err.GetMessage()); } - return tmp.substr(offset.GetValue(), length.GetValue()); + return tmp.substr(offset.GetValue(), *length); } inline std::string ThinString::ToString(Error& err) { diff --git a/src/llv8.cc b/src/llv8.cc index 4c453cfd..4747d56a 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -80,6 +80,20 @@ int64_t LLV8::LoadPtr(int64_t addr, Error& err) { return value; } +template +CheckedType LLV8::LoadUnsigned(int64_t addr, uint32_t byte_size) { + SBError sberr; + int64_t value = process_.ReadUnsignedFromMemory(static_cast(addr), + byte_size, sberr); + + if (sberr.Fail()) { + PRINT_DEBUG("Failed to load unsigned from v8 memory. Reason: %s", + sberr.GetCString()); + return CheckedType(); + } + + return CheckedType(value); +} int64_t LLV8::LoadUnsigned(int64_t addr, uint32_t byte_size, Error& err) { SBError sberr; diff --git a/src/llv8.h b/src/llv8.h index bd660309..27a30ecb 100644 --- a/src/llv8.h +++ b/src/llv8.h @@ -163,7 +163,7 @@ class String : public HeapObject { inline int64_t Encoding(Error& err); inline CheckedType Representation(Error& err); - inline Smi Length(Error& err); + inline CheckedType Length(Error& err); std::string ToString(Error& err); @@ -605,8 +605,13 @@ class LLV8 { template inline T LoadValue(int64_t addr, Error& err); + template + inline T LoadValue(int64_t addr); + int64_t LoadConstant(const char* name); int64_t LoadPtr(int64_t addr, Error& err); + template + CheckedType LoadUnsigned(int64_t addr, uint32_t byte_size); int64_t LoadUnsigned(int64_t addr, uint32_t byte_size, Error& err); double LoadDouble(int64_t addr, Error& err); std::string LoadBytes(int64_t addr, int64_t length, Error& err);