add sto APIs

This commit is contained in:
tequ
2025-09-29 13:38:05 +09:00
parent e3c4644151
commit 4ff8d688e2
3 changed files with 519 additions and 416 deletions

View File

@@ -43,11 +43,22 @@ public:
// util_keylet
/// sto APIs
// sto_validate
// sto_subfield
// sto_subarray
// sto_emplace
// sto_erase
Expected<bool, HookReturnCode>
sto_validate(Bytes const& data) const;
Expected<std::pair<uint32_t, uint32_t>, HookReturnCode>
sto_subfield(Bytes const& data, uint32_t field_id) const;
Expected<std::pair<uint32_t, uint32_t>, HookReturnCode>
sto_subarray(Bytes const& data, uint32_t index_id) const;
Expected<Bytes, HookReturnCode>
sto_emplace(
Bytes const& source_object,
std::optional<Bytes> const& field_object,
uint32_t field_id) const;
// sto_erase: same as sto_emplace with field_object = nullopt
/// etxn APIs
Expected<std::shared_ptr<Transaction>, HookReturnCode>
@@ -193,7 +204,8 @@ public:
ledger_keylet(Keylet const& klLo, Keylet const& klHi) const;
/// state APIs
// state
// state: same as state_foreign with ns = 0 and account = hook_account()
Expected<Bytes, HookReturnCode>
state_foreign(
@@ -201,7 +213,8 @@ public:
uint256 const& ns,
AccountID const& account) const;
// state_set
// state_set: same as state_foreign_set with ns = 0 and account =
// hook_account()
Expected<uint64_t, HookReturnCode>
state_foreign_set(
@@ -301,6 +314,30 @@ private:
uint256 const& key,
Bytes const& data,
bool modified) const;
// these are only used by get_stobject_length below
enum parse_error {
pe_unexpected_end = -1,
pe_unknown_type_early = -2, // detected early
pe_unknown_type_late = -3, // end of function
pe_excessive_nesting = -4,
pe_excessive_size = -5
};
inline Expected<
int32_t,
parse_error>
get_stobject_length(
unsigned char* start, // in - begin iterator
unsigned char* maxptr, // in - end iterator
int& type, // out - populated by serialized type code
int& field, // out - populated by serialized field code
int& payload_start, // out - the start of actual payload data for
// this type
int& payload_length, // out - the length of actual payload data for
// this type
int recursion_depth = 0) // used internally
const;
};
} // namespace hook

View File

@@ -14,6 +14,8 @@
#include <ripple/protocol/STObject.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/protocol/tokens.h>
#include "ripple/basics/Expected.h"
#include "test/jtx/utility.h"
#include <cfenv>
namespace hook {
@@ -335,10 +337,246 @@ HookAPI::util_sha512h(Slice const& data) const
// util_keylet
/// sto APIs
// sto_validate
// sto_subfield
// sto_subarray
// sto_emplace
Expected<bool, HookReturnCode>
HookAPI::sto_validate(Bytes const& data) const
{
if (data.size() < 2)
return Unexpected(TOO_SMALL);
unsigned char* start = const_cast<unsigned char*>(data.data());
unsigned char* upto = start;
unsigned char* end = start + data.size();
for (int i = 0; i < 1024 && upto < end; ++i)
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
auto const length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
if (!length)
return 0;
upto += length.value();
}
return upto == end ? 1 : 0;
}
Expected<std::pair<uint32_t, uint32_t>, HookReturnCode>
HookAPI::sto_subfield(Bytes const& data, uint32_t field_id) const
{
if (data.size() < 2)
return Unexpected(TOO_SMALL);
unsigned char* start = const_cast<unsigned char*>(data.data());
unsigned char* upto = start;
unsigned char* end = start + data.size();
DBG_PRINTF(
"sto_subfield called, looking for field %u type %u\n",
field_id & 0xFFFF,
(field_id >> 16));
for (int j = -5; j < 5; ++j)
DBG_PRINTF((j == 0 ? " >%02X< " : " %02X "), *(start + j));
DBG_PRINTF("\n");
// if ((*upto & 0xF0) == 0xE0)
// upto++;
for (int i = 0; i < 1024 && upto < end; ++i)
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
auto const length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
if (!length)
return Unexpected(PARSE_ERROR);
if ((type << 16) + field == field_id)
{
DBG_PRINTF(
"sto_subfield returned for field %u type %u\n",
field_id & 0xFFFF,
(field_id >> 16));
for (int j = -5; j < 5; ++j)
DBG_PRINTF((j == 0 ? " [%02X] " : " %02X "), *(upto + j));
DBG_PRINTF("\n");
if (type == 0xF) // we return arrays fully formed
return std::make_pair(upto - start, length.value());
// return pointers to all other objects as payloads
return std::make_pair(upto - start + payload_start, payload_length);
}
upto += length.value();
}
if (upto != end)
return Unexpected(PARSE_ERROR);
return Unexpected(DOESNT_EXIST);
}
Expected<std::pair<uint32_t, uint32_t>, HookReturnCode>
HookAPI::sto_subarray(Bytes const& data, uint32_t index_id) const
{
if (data.size() < 2)
return Unexpected(TOO_SMALL);
unsigned char* start = const_cast<unsigned char*>(data.data());
unsigned char* upto = start;
unsigned char* end = start + data.size();
// unwrap the array if it is wrapped,
// by removing a byte from the start and end
if ((*upto & 0xF0U) == 0xF0U)
{
upto++;
end--;
}
if (upto >= end)
return Unexpected(PARSE_ERROR);
/*
DBG_PRINTF("sto_subarray called, looking for index %u\n", index_id);
for (int j = -5; j < 5; ++j)
printf(( j == 0 ? " >%02X< " : " %02X "), *(start + j));
DBG_PRINTF("\n");
*/
for (int i = 0; i < 1024 && upto < end; ++i)
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
auto const length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
if (!length)
return Unexpected(PARSE_ERROR);
if (i == index_id)
{
DBG_PRINTF("sto_subarray returned for index %u\n", index_id);
for (int j = -5; j < 5; ++j)
DBG_PRINTF(
(j == 0 ? " [%02X] " : " %02X "),
*(upto + j + length.value()));
DBG_PRINTF("\n");
return std::make_pair(upto - start, length.value());
}
upto += length.value();
}
if (upto != end)
return Unexpected(PARSE_ERROR);
return Unexpected(DOESNT_EXIST);
}
Expected<Bytes, HookReturnCode>
HookAPI::sto_emplace(
Bytes const& source_object,
std::optional<Bytes> const& field_object,
uint32_t field_id) const
{
// RH TODO: put these constants somewhere (votable?)
if (source_object.size() > 1024 * 16)
return Unexpected(TOO_BIG);
if (source_object.size() < 2)
return Unexpected(TOO_SMALL);
if (!field_object.has_value())
{
// this is a delete operation
}
else
{
if (field_object->size() > 4096)
return Unexpected(TOO_BIG);
if (field_object->size() < 2)
return Unexpected(TOO_SMALL);
}
std::vector<uint8_t> out(
(size_t)(
source_object.size() + (field_object ? field_object->size() : 0)),
(uint8_t)0);
uint8_t* write_ptr = out.data();
// we must inject the field at the canonical location....
// so find that location
unsigned char* start = const_cast<unsigned char*>(source_object.data());
unsigned char* upto = start;
unsigned char* end = start + source_object.size();
unsigned char* inject_start = end;
unsigned char* inject_end = end;
DBG_PRINTF(
"sto_emplace called, looking for field %u type %u\n",
field_id & 0xFFFF,
(field_id >> 16));
for (int j = -5; j < 5; ++j)
DBG_PRINTF((j == 0 ? " >%02X< " : " %02X "), *(start + j));
DBG_PRINTF("\n");
for (int i = 0; i < 1024 && upto < end; ++i)
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
auto const length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
if (!length)
return Unexpected(PARSE_ERROR);
if ((type << 16) + field == field_id)
{
inject_start = upto;
inject_end = upto + length.value();
break;
}
else if ((type << 16) + field > field_id)
{
inject_start = upto;
inject_end = upto;
break;
}
upto += length.value();
}
// if the scan loop ends past the end of the source object
// then the source object is invalid/corrupt, so we must
// return an error
if (upto > end)
return Unexpected(PARSE_ERROR);
// upto is injection point
int64_t bytes_written = 0;
// part 1
if (inject_start - start > 0)
{
size_t len = inject_start - start;
memcpy(write_ptr, start, len);
bytes_written += len;
}
if (field_object && field_object->size() > 0)
{
// write the field (or don't if it's a delete operation)
memcpy(
write_ptr + bytes_written,
field_object->data(),
field_object->size());
bytes_written += field_object->size();
}
// part 2
if (end - inject_end > 0)
{
size_t len = end - inject_end;
memcpy(write_ptr + bytes_written, inject_end, len);
bytes_written += len;
}
out.resize(bytes_written);
return out;
}
// sto_erase
/// etxn APIs
@@ -2507,4 +2745,199 @@ HookAPI::set_state_cache(
return 1;
}
// RH NOTE this is a light-weight stobject parsing function for drilling into a
// provided serialzied object however it could probably be replaced by an
// existing class or routine or set of routines in XRPLD Returns object length
// including header bytes (and footer bytes in the event of array or object)
// negative indicates error
inline Expected<
int32_t,
HookAPI::parse_error>
HookAPI::get_stobject_length(
unsigned char* start, // in - begin iterator
unsigned char* maxptr, // in - end iterator
int& type, // out - populated by serialized type code
int& field, // out - populated by serialized field code
int& payload_start, // out - the start of actual payload data for this type
int& payload_length, // out - the length of actual payload data for this
// type
int recursion_depth) // used internally
const
{
if (recursion_depth > 10)
return Unexpected(pe_excessive_nesting);
unsigned char* end = maxptr;
unsigned char* upto = start;
int high = *upto >> 4;
int low = *upto & 0xF;
upto++;
if (upto >= end)
return Unexpected(pe_unexpected_end);
if (high > 0 && low > 0)
{
// common type common field
type = high;
field = low;
}
else if (high > 0)
{
// common type, uncommon field
type = high;
field = *upto++;
}
else if (low > 0)
{
// common field, uncommon type
field = low;
type = *upto++;
}
else
{
// uncommon type and field
type = *upto++;
if (upto >= end)
return Unexpected(pe_unexpected_end);
field = *upto++;
}
DBG_PRINTF(
"%d get_st_object found field %d type %d\n",
recursion_depth,
field,
type);
if (upto >= end)
return pe_unexpected_end;
// RH TODO: link this to rippled's internal STObject constants
// E.g.:
/*
int field_code = (safe_cast<int>(type) << 16) | field;
auto const& fieldObj = ripple::SField::getField;
*/
if (type < 1 || type > 19 || (type >= 9 && type <= 13))
return Unexpected(pe_unknown_type_early);
bool is_vl = (type == 8 /*ACCID*/ || type == 7 || type == 18 || type == 19);
int length = -1;
if (is_vl)
{
length = *upto++;
if (upto >= end)
return Unexpected(pe_unexpected_end);
if (length < 193)
{
// do nothing
}
else if (length > 192 && length < 241)
{
length -= 193;
length *= 256;
length += *upto++ + 193;
if (upto > end)
return Unexpected(pe_unexpected_end);
}
else
{
int b2 = *upto++;
if (upto >= end)
return Unexpected(pe_unexpected_end);
length -= 241;
length *= 65536;
length += 12481 + (b2 * 256) + *upto++;
if (upto >= end)
return Unexpected(pe_unexpected_end);
}
}
else if ((type >= 1 && type <= 5) || type == 16 || type == 17)
{
length =
(type == 1
? 2
: (type == 2
? 4
: (type == 3
? 8
: (type == 4
? 16
: (type == 5
? 32
: (type == 16
? 1
: (type == 17 ? 20
: -1)))))));
}
else if (type == 6) /* AMOUNT */
{
length = (*upto >> 6 == 1) ? 8 : 48;
if (upto >= end)
return Unexpected(pe_unexpected_end);
}
if (length > -1)
{
payload_start = upto - start;
payload_length = length;
DBG_PRINTF(
"%d get_stobject_length field: %d Type: %d VL: %s Len: %d "
"Payload_Start: %d Payload_Len: %d\n",
recursion_depth,
field,
type,
(is_vl ? "yes" : "no"),
length,
payload_start,
payload_length);
return length + (upto - start);
}
if (type == 15 || type == 14) /* Object / Array */
{
payload_start = upto - start;
for (int i = 0; i < 1024; ++i)
{
int subfield = -1, subtype = -1, payload_start_ = -1,
payload_length_ = -1;
auto const sublength = get_stobject_length(
upto,
end,
subtype,
subfield,
payload_start_,
payload_length_,
recursion_depth + 1);
DBG_PRINTF(
"%d get_stobject_length i %d %d-%d, upto %d sublength %d\n",
recursion_depth,
i,
subtype,
subfield,
upto - start,
sublength);
if (!sublength)
return Unexpected(pe_unexpected_end);
upto += sublength.value();
if (upto >= end)
return Unexpected(pe_unexpected_end);
if ((*upto == 0xE1U && type == 0xEU) ||
(*upto == 0xF1U && type == 0xFU))
{
payload_length = upto - start - payload_start;
upto++;
return (upto - start);
}
}
return Unexpected(pe_excessive_size);
}
return Unexpected(pe_unknown_type_late);
};
} // namespace hook

View File

@@ -2993,207 +2993,6 @@ DEFINE_HOOK_FUNCTION(
HOOK_TEARDOWN();
}
// these are only used by get_stobject_length below
enum parse_error : int32_t {
pe_unexpected_end = -1,
pe_unknown_type_early = -2, // detected early
pe_unknown_type_late = -3, // end of function
pe_excessive_nesting = -4,
pe_excessive_size = -5
};
// RH NOTE this is a light-weight stobject parsing function for drilling into a
// provided serialzied object however it could probably be replaced by an
// existing class or routine or set of routines in XRPLD Returns object length
// including header bytes (and footer bytes in the event of array or object)
// negative indicates error
inline int32_t
get_stobject_length(
unsigned char* start, // in - begin iterator
unsigned char* maxptr, // in - end iterator
int& type, // out - populated by serialized type code
int& field, // out - populated by serialized field code
int& payload_start, // out - the start of actual payload data for this type
int& payload_length, // out - the length of actual payload data for this
// type
int recursion_depth = 0) // used internally
{
if (recursion_depth > 10)
return pe_excessive_nesting;
unsigned char* end = maxptr;
unsigned char* upto = start;
int high = *upto >> 4;
int low = *upto & 0xF;
upto++;
if (upto >= end)
return pe_unexpected_end;
if (high > 0 && low > 0)
{
// common type common field
type = high;
field = low;
}
else if (high > 0)
{
// common type, uncommon field
type = high;
field = *upto++;
}
else if (low > 0)
{
// common field, uncommon type
field = low;
type = *upto++;
}
else
{
// uncommon type and field
type = *upto++;
if (upto >= end)
return pe_unexpected_end;
field = *upto++;
}
DBG_PRINTF(
"%d get_st_object found field %d type %d\n",
recursion_depth,
field,
type);
if (upto >= end)
return pe_unexpected_end;
// RH TODO: link this to rippled's internal STObject constants
// E.g.:
/*
int field_code = (safe_cast<int>(type) << 16) | field;
auto const& fieldObj = ripple::SField::getField;
*/
if (type < 1 || type > 19 || (type >= 9 && type <= 13))
return pe_unknown_type_early;
bool is_vl = (type == 8 /*ACCID*/ || type == 7 || type == 18 || type == 19);
int length = -1;
if (is_vl)
{
length = *upto++;
if (upto >= end)
return pe_unexpected_end;
if (length < 193)
{
// do nothing
}
else if (length > 192 && length < 241)
{
length -= 193;
length *= 256;
length += *upto++ + 193;
if (upto > end)
return pe_unexpected_end;
}
else
{
int b2 = *upto++;
if (upto >= end)
return pe_unexpected_end;
length -= 241;
length *= 65536;
length += 12481 + (b2 * 256) + *upto++;
if (upto >= end)
return pe_unexpected_end;
}
}
else if ((type >= 1 && type <= 5) || type == 16 || type == 17)
{
length =
(type == 1
? 2
: (type == 2
? 4
: (type == 3
? 8
: (type == 4
? 16
: (type == 5
? 32
: (type == 16
? 1
: (type == 17 ? 20
: -1)))))));
}
else if (type == 6) /* AMOUNT */
{
length = (*upto >> 6 == 1) ? 8 : 48;
if (upto >= end)
return pe_unexpected_end;
}
if (length > -1)
{
payload_start = upto - start;
payload_length = length;
DBG_PRINTF(
"%d get_stobject_length field: %d Type: %d VL: %s Len: %d "
"Payload_Start: %d Payload_Len: %d\n",
recursion_depth,
field,
type,
(is_vl ? "yes" : "no"),
length,
payload_start,
payload_length);
return length + (upto - start);
}
if (type == 15 || type == 14) /* Object / Array */
{
payload_start = upto - start;
for (int i = 0; i < 1024; ++i)
{
int subfield = -1, subtype = -1, payload_start_ = -1,
payload_length_ = -1;
int32_t sublength = get_stobject_length(
upto,
end,
subtype,
subfield,
payload_start_,
payload_length_,
recursion_depth + 1);
DBG_PRINTF(
"%d get_stobject_length i %d %d-%d, upto %d sublength %d\n",
recursion_depth,
i,
subtype,
subfield,
upto - start,
sublength);
if (sublength < 0)
return pe_unexpected_end;
upto += sublength;
if (upto >= end)
return pe_unexpected_end;
if ((*upto == 0xE1U && type == 0xEU) ||
(*upto == 0xF1U && type == 0xFU))
{
payload_length = upto - start - payload_start;
upto++;
return (upto - start);
}
}
return pe_excessive_size;
}
return pe_unknown_type_late;
}
// Given an serialized object in memory locate and return the offset and length
// of the payload of a subfield of that object. Arrays are returned fully
// formed. If successful returns offset and length joined as int64_t. Use
@@ -3211,58 +3010,13 @@ DEFINE_HOOK_FUNCTION(
if (NOT_IN_BOUNDS(read_ptr, read_len, memory_length))
return OUT_OF_BOUNDS;
if (read_len < 2)
return TOO_SMALL;
unsigned char* start = (unsigned char*)(memory + read_ptr);
unsigned char* upto = start;
unsigned char* end = start + read_len;
DBG_PRINTF(
"sto_subfield called, looking for field %u type %u\n",
field_id & 0xFFFF,
(field_id >> 16));
for (int j = -5; j < 5; ++j)
DBG_PRINTF((j == 0 ? " >%02X< " : " %02X "), *(start + j));
DBG_PRINTF("\n");
// if ((*upto & 0xF0) == 0xE0)
// upto++;
for (int i = 0; i < 1024 && upto < end; ++i)
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
int32_t length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
if (length < 0)
return PARSE_ERROR;
if ((type << 16) + field == field_id)
{
DBG_PRINTF(
"sto_subfield returned for field %u type %u\n",
field_id & 0xFFFF,
(field_id >> 16));
for (int j = -5; j < 5; ++j)
DBG_PRINTF((j == 0 ? " [%02X] " : " %02X "), *(upto + j));
DBG_PRINTF("\n");
if (type == 0xF) // we return arrays fully formed
return (((int64_t)(upto - start))
<< 32) /* start of the object */
+ (uint32_t)(length);
// return pointers to all other objects as payloads
return (((int64_t)(upto - start + payload_start))
<< 32U) /* start of the object */
+ (uint32_t)(payload_length);
}
upto += length;
}
if (upto != end)
return PARSE_ERROR;
return DOESNT_EXIST;
hook::HookAPI api(hookCtx);
Bytes data{memory + read_ptr, memory + read_ptr + read_len};
auto const result = api.sto_subfield(data, field_id);
if (!result)
return result.error();
auto const& pair = result.value();
return (uint64_t(pair.first) << 32U) + (uint32_t)pair.second;
HOOK_TEARDOWN();
}
@@ -3281,56 +3035,13 @@ DEFINE_HOOK_FUNCTION(
if (NOT_IN_BOUNDS(read_ptr, read_len, memory_length))
return OUT_OF_BOUNDS;
if (read_len < 2)
return TOO_SMALL;
unsigned char* start = (unsigned char*)(memory + read_ptr);
unsigned char* upto = start;
unsigned char* end = start + read_len;
// unwrap the array if it is wrapped,
// by removing a byte from the start and end
if ((*upto & 0xF0U) == 0xF0U)
{
upto++;
end--;
}
if (upto >= end)
return PARSE_ERROR;
/*
DBG_PRINTF("sto_subarray called, looking for index %u\n", index_id);
for (int j = -5; j < 5; ++j)
printf(( j == 0 ? " >%02X< " : " %02X "), *(start + j));
DBG_PRINTF("\n");
*/
for (int i = 0; i < 1024 && upto < end; ++i)
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
int32_t length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
if (length < 0)
return PARSE_ERROR;
if (i == index_id)
{
DBG_PRINTF("sto_subarray returned for index %u\n", index_id);
for (int j = -5; j < 5; ++j)
DBG_PRINTF(
(j == 0 ? " [%02X] " : " %02X "), *(upto + j + length));
DBG_PRINTF("\n");
return (((int64_t)(upto - start)) << 32U) /* start of the object */
+ (int64_t)(length);
}
upto += length;
}
if (upto != end)
return PARSE_ERROR;
return DOESNT_EXIST;
hook::HookAPI api(hookCtx);
Bytes data{memory + read_ptr, memory + read_ptr + read_len};
auto const result = api.sto_subarray(data, index_id);
if (!result)
return result.error();
auto const& pair = result.value();
return (uint64_t(pair.first) << 32U) + (uint32_t)pair.second;
HOOK_TEARDOWN();
}
@@ -3526,92 +3237,26 @@ DEFINE_HOOK_FUNCTION(
return MEM_OVERLAP;
}
// we must inject the field at the canonical location....
// so find that location
unsigned char* start = (unsigned char*)(memory + sread_ptr);
unsigned char* upto = start;
unsigned char* end = start + sread_len;
unsigned char* inject_start = end;
unsigned char* inject_end = end;
hook::HookAPI api(hookCtx);
Bytes source{memory + sread_ptr, memory + sread_ptr + sread_len};
std::optional<Bytes> field;
if (fread_len > 0 && fread_ptr > 0)
field = Bytes{memory + fread_ptr, memory + fread_ptr + fread_len};
auto const result = api.sto_emplace(source, field, field_id);
if (!result)
return result.error();
auto const& bytes = result.value();
DBG_PRINTF(
"sto_emplace called, looking for field %u type %u\n",
field_id & 0xFFFF,
(field_id >> 16));
for (int j = -5; j < 5; ++j)
DBG_PRINTF((j == 0 ? " >%02X< " : " %02X "), *(start + j));
DBG_PRINTF("\n");
if (bytes.size() > write_len)
return INTERNAL_ERROR;
for (int i = 0; i < 1024 && upto < end; ++i)
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
int32_t length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
if (length < 0)
return PARSE_ERROR;
if ((type << 16) + field == field_id)
{
inject_start = upto;
inject_end = upto + length;
break;
}
else if ((type << 16) + field > field_id)
{
inject_start = upto;
inject_end = upto;
break;
}
upto += length;
}
// if the scan loop ends past the end of the source object
// then the source object is invalid/corrupt, so we must
// return an error
if (upto > end)
return PARSE_ERROR;
// upto is injection point
int64_t bytes_written = 0;
// part 1
if (inject_start - start > 0)
{
WRITE_WASM_MEMORY(
bytes_written,
write_ptr,
write_len,
start,
(inject_start - start),
memory,
memory_length);
}
if (fread_len > 0)
{
// write the field (or don't if it's a delete operation)
WRITE_WASM_MEMORY(
bytes_written,
(write_ptr + bytes_written),
(write_len - bytes_written),
memory + fread_ptr,
fread_len,
memory,
memory_length);
}
// part 2
if (end - inject_end > 0)
{
WRITE_WASM_MEMORY(
bytes_written,
(write_ptr + bytes_written),
(write_len - bytes_written),
inject_end,
(end - inject_end),
memory,
memory_length);
}
return bytes_written;
WRITE_WASM_MEMORY_AND_RETURN(
write_ptr,
write_len,
bytes.data(),
bytes.size(),
memory,
memory_length);
HOOK_TEARDOWN();
}
@@ -3660,24 +3305,12 @@ DEFINE_HOOK_FUNCTION(
if (NOT_IN_BOUNDS(read_ptr, read_len, memory_length))
return OUT_OF_BOUNDS;
if (read_len < 2)
return TOO_SMALL;
unsigned char* start = (unsigned char*)(memory + read_ptr);
unsigned char* upto = start;
unsigned char* end = start + read_len;
for (int i = 0; i < 1024 && upto < end; ++i)
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
int32_t length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
if (length < 0)
return 0;
upto += length;
}
return upto == end ? 1 : 0;
Bytes data{read_ptr + memory, read_ptr + read_len + memory};
hook::HookAPI api(hookCtx);
auto const result = api.sto_validate(data);
if (!result)
return result.error();
return result.value() ? 1 : 0;
HOOK_TEARDOWN();
}