Skip to content

Commit

Permalink
src: fix String::Length for Node.js v12.3.0
Browse files Browse the repository at this point in the history
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: #302
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information
mmarchini committed Oct 7, 2019
1 parent 2964af5 commit a79a008
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 16 deletions.
5 changes: 5 additions & 0 deletions src/llv8-constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}


Expand Down
1 change: 1 addition & 0 deletions src/llv8-constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ class String : public Module {
int64_t kThinStringTag;

int64_t kLengthOffset;
bool kLengthIsSmi;

protected:
void Load();
Expand Down
51 changes: 36 additions & 15 deletions src/llv8-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ inline int32_t LLV8::LoadValue<int32_t>(int64_t addr, Error& err) {
return LoadUnsigned(addr, 4, err);
}

template <>
inline CheckedType<int32_t> LLV8::LoadValue<CheckedType<int32_t>>(
int64_t addr) {
return LoadUnsigned<int32_t>(addr, 4);
}

template <class T>
inline T LLV8::LoadValue(int64_t addr, Error& err) {
int64_t ptr;
Expand Down Expand Up @@ -363,7 +369,23 @@ inline int64_t String::Encoding(Error& err) {
return type & v8()->string()->kEncodingMask;
}

ACCESSOR(String, Length, string()->kLengthOffset, Smi)
inline CheckedType<int32_t> String::Length(Error& err) {
RETURN_IF_INVALID((*this), CheckedType<int32_t>());

if (v8()->string()->kLengthIsSmi) {
Smi len = LoadFieldValue<Smi>(v8()->string()->kLengthOffset, err);
RETURN_IF_INVALID(len, CheckedType<int32_t>());

return CheckedType<int32_t>(len.GetValue());
}

CheckedType<int32_t> len = v8()->LoadValue<CheckedType<int32_t>>(
LeaField(v8()->string()->kLengthOffset));
RETURN_IF_INVALID(len, CheckedType<int32_t>());

return len;
}


ACCESSOR(Script, Name, script()->kNameOffset, String)
ACCESSOR(Script, LineOffset, script()->kLineOffsetOffset, Smi)
Expand Down Expand Up @@ -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<int32_t> 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<int32_t> len = Length(err);
RETURN_IF_INVALID(len, std::string());
return v8()->LoadTwoByteString(chars, *len, err);
}

inline std::string ConsString::ToString(Error& err) {
Expand Down Expand Up @@ -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<int32_t> 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) {
Expand Down
14 changes: 14 additions & 0 deletions src/llv8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@ int64_t LLV8::LoadPtr(int64_t addr, Error& err) {
return value;
}

template <class T>
CheckedType<T> LLV8::LoadUnsigned(int64_t addr, uint32_t byte_size) {
SBError sberr;
int64_t value = process_.ReadUnsignedFromMemory(static_cast<addr_t>(addr),
byte_size, sberr);

if (sberr.Fail()) {
PRINT_DEBUG("Failed to load unsigned from v8 memory. Reason: %s",
sberr.GetCString());
return CheckedType<T>();
}

return CheckedType<T>(value);
}

int64_t LLV8::LoadUnsigned(int64_t addr, uint32_t byte_size, Error& err) {
SBError sberr;
Expand Down
7 changes: 6 additions & 1 deletion src/llv8.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class String : public HeapObject {

inline int64_t Encoding(Error& err);
inline CheckedType<int64_t> Representation(Error& err);
inline Smi Length(Error& err);
inline CheckedType<int32_t> Length(Error& err);

std::string ToString(Error& err);

Expand Down Expand Up @@ -605,8 +605,13 @@ class LLV8 {
template <class T>
inline T LoadValue(int64_t addr, Error& err);

template <class T>
inline T LoadValue(int64_t addr);

int64_t LoadConstant(const char* name);
int64_t LoadPtr(int64_t addr, Error& err);
template <class T>
CheckedType<T> 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);
Expand Down

0 comments on commit a79a008

Please sign in to comment.