initial version of hook str api

This commit is contained in:
Richard Holland
2022-10-06 08:11:49 +00:00
parent e99ffe29a3
commit 04a938377d
4 changed files with 260 additions and 4 deletions

View File

@@ -219,7 +219,7 @@ namespace hook_api
COMPLEX_NOT_SUPPORTED = -39,
DOES_NOT_MATCH = -40, // two keylets were required to be the same type but werent
INVALID_KEY = -41, // user supplied key was not valid
NOT_A_STRING = -42, // nul terminator missing from a string argument
};
enum ExitType : uint8_t
@@ -319,7 +319,12 @@ namespace hook_api
"hook_skip",
"hook_again",
"hook_namespace",
"meta_slot"
"meta_slot",
"str_find",
"str_replace",
"str_concat",
"str_format",
"str_compare"
};
};
#endif

View File

@@ -20,8 +20,8 @@
#define EMPTY()
#define DEFER(id) id EMPTY()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define VA_NARGS(__drop, ...) VA_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
#define VA_NARGS(__drop, ...) VA_NARGS_IMPL(__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define FIRST(a, b) a
#define SECOND(a, b) b
#define STRIP_TYPES(...) FOR_VARS(SECOND, 0, __VA_ARGS__)
@@ -41,6 +41,8 @@
#define FOR_VAR_8(T, S, a, ...) FOR_VAR_1(T, S, a) DELIM(S) FOR_VAR_7(T, S, __VA_ARGS__)
#define FOR_VAR_9(T, S, a, ...) FOR_VAR_1(T, S, a) DELIM(S) FOR_VAR_8(T, S, __VA_ARGS__)
#define FOR_VAR_10(T, S, a, ...) FOR_VAR_1(T, S, a) DELIM(S) FOR_VAR_9(T, S, __VA_ARGS__)
#define FOR_VAR_11(T, S, a, ...) FOR_VAR_1(T, S, a) DELIM(S) FOR_VAR_10(T, S, __VA_ARGS__)
#define FOR_VAR_12(T, S, a, ...) FOR_VAR_1(T, S, a) DELIM(S) FOR_VAR_11(T, S, __VA_ARGS__)
#define FOR_VARS(T, S, ...)\
DEFER(CAT(FOR_VAR_,VA_NARGS(NULL, __VA_ARGS__))CAT(LPAREN T COMMA S COMMA OBSTRUCT(__VA_ARGS__) RPAREN))

View File

@@ -222,6 +222,26 @@ namespace hook_api
DECLARE_HOOK_FUNCTION(int64_t, meta_slot, uint32_t slot_no );
DECLARE_HOOK_FUNCTION(int64_t, str_find, uint32_t hread_ptr, uint32_t hread_len,
uint32_t nread_ptr, uint32_t nread_len,
uint32_t mode, uint32_t n);
DECLARE_HOOK_FUNCTION(int64_t, str_replace, uint32_t write_ptr, uint32_t write_len,
uint32_t hread_ptr, uint32_t hread_len,
uint32_t nread_ptr, uint32_t nread_len,
uint32_t rread_ptr, uint32_t rread_len,
uint32_t mode, uint32_t n);
DECLARE_HOOK_FUNCTION(int64_t, str_compare, uint32_t fread_ptr, uint32_t fread_len,
uint32_t sread_ptr, uint32_t sread_len,
uint32_t mode);
DECLARE_HOOK_FUNCTION(int64_t, str_format, uint32_t write_ptr, uint32_t write_len,
uint32_t fread_ptr, uint32_t fread_len,
uint64_t a, uint64_t b, uint64_t c, uint64_t d,
uint64_t e, uint64_t f, uint64_t g, uint64_t h);
DECLARE_HOOK_FUNCTION(int64_t, str_concat, uint32_t write_ptr, uint32_t write_len,
uint32_t read_ptr, uint32_t read_len,
uint64_t operand, uint32_t operand_type);
} /* end namespace hook_api */
namespace hook
@@ -631,6 +651,13 @@ namespace hook
ADD_HOOK_FUNCTION(meta_slot, ctx);
ADD_HOOK_FUNCTION(str_find, ctx);
ADD_HOOK_FUNCTION(str_replace, ctx);
ADD_HOOK_FUNCTION(str_compare, ctx);
ADD_HOOK_FUNCTION(str_concat, ctx);
ADD_HOOK_FUNCTION(str_format, ctx);
WasmEdge_TableInstanceContext* hostTable = WasmEdge_TableInstanceCreate(tableType);
WasmEdge_ImportObjectAddTable(importObj, tableName, hostTable);
WasmEdge_MemoryInstanceContext* hostMem = WasmEdge_MemoryInstanceCreate(memType);

View File

@@ -5058,3 +5058,225 @@ DEFINE_HOOK_FUNCTION(
return slot_into;
}
DEFINE_HOOK_FUNCTION(
int64_t,
str_find,
uint32_t hread_ptr, uint32_t hread_len,
uint32_t nread_ptr, uint32_t nread_len,
uint32_t mode, uint32_t n)
{
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx, hookCtx on current stack
if (NOT_IN_BOUNDS(hread_ptr, hread_len, memory_length) ||
NOT_IN_BOUNDS(nread_ptr, nread_len, memory_length))
return OUT_OF_BOUNDS;
if (hread_len > 32*1024)
return TOO_BIG;
if (nread_len > 256)
return TOO_BIG;
if (hread_len == 0)
return TOO_SMALL;
if (mode > 3)
return INVALID_ARGUMENT;
if (n >= hread_len)
return INVALID_ARGUMENT;
// overload for str_len
if (nread_ptr == 0)
{
if (nread_len != 0)
return INVALID_ARGUMENT;
return strnlen((const char*)(hread_ptr + memory), hread_len);
}
bool insensitive = mode % 2 == 1;
// just the haystack based on where to start search from
hread_ptr += n;
hread_len -= n;
if (NOT_IN_BOUNDS(hread_ptr, hread_len, memory_length))
return OUT_OF_BOUNDS;
std::string_view haystack{(const char*)(memory + hread_ptr), hread_len};
if (mode < 2)
{
// plain string mode: 0 == case sensitive
std::string_view needle{(const char*)(memory + nread_ptr), nread_len};
auto found = std::search(
haystack.begin(), haystack.end(),
needle.begin(), needle.end(),
insensitive
? [](char ch1, char ch2)
{
return std::toupper(ch1) == std::toupper(ch2);
}
: [](char ch1, char ch2)
{
return ch1 == ch2;
}
);
if (found == haystack.end())
return DOESNT_EXIST;
return found - haystack.begin();
}
else
{
// regex mode mode: 2 == case sensitive
return NOT_IMPLEMENTED;
}
}
DEFINE_HOOK_FUNCTION(
int64_t,
str_replace,
uint32_t write_ptr, uint32_t write_len,
uint32_t hread_ptr, uint32_t hread_len,
uint32_t nread_ptr, uint32_t nread_len,
uint32_t rread_ptr, uint32_t rread_len,
uint32_t mode, uint32_t n)
{
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx, hookCtx on current stack
if (NOT_IN_BOUNDS(write_ptr, write_len, memory_length) ||
NOT_IN_BOUNDS(hread_ptr, hread_len, memory_length) ||
NOT_IN_BOUNDS(nread_ptr, nread_len, memory_length) ||
NOT_IN_BOUNDS(rread_ptr, rread_len, memory_length))
return OUT_OF_BOUNDS;
if (hread_len > 32*1024)
return TOO_BIG;
if (nread_len > 256)
return TOO_BIG;
if (hread_len == 0)
return TOO_SMALL;
if (nread_len == 0)
return TOO_SMALL;
return NOT_IMPLEMENTED;
}
DEFINE_HOOK_FUNCTION(
int64_t,
str_compare,
uint32_t fread_ptr, uint32_t fread_len,
uint32_t sread_ptr, uint32_t sread_len,
uint32_t mode)
{
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx, hookCtx on current stack
if (NOT_IN_BOUNDS(fread_ptr, fread_len, memory_length) ||
NOT_IN_BOUNDS(sread_ptr, sread_len, memory_length))
return OUT_OF_BOUNDS;
if (mode > 1)
return INVALID_ARGUMENT;
if (fread_len > 255 || sread_len > 255)
return TOO_BIG;
if (fread_len == 0 || sread_len == 0)
return TOO_SMALL;
bool insensitive = mode == 1;
const char* it1 = (const char*)(memory + fread_ptr);
const char* it2 = (const char*)(memory + sread_ptr);
const char* end1 = it1 + fread_len;
const char* end2 = it2 + sread_len;
if (insensitive)
for(; it1 < end1 && it2 < end2; ++it1, ++it2)
{
if (*it1 < *it2)
return 0;
if (*it1 > *it2)
return 2;
}
else
for(; it1 < end1 && it2 < end2; ++it1, ++it2)
{
if (std::tolower(*it1) < std::tolower(*it2))
return 0;
if (std::tolower(*it1) > std::tolower(*it2))
return 2;
}
return 1;
}
DEFINE_HOOK_FUNCTION(
int64_t,
str_format,
uint32_t write_ptr, uint32_t write_len,
uint32_t fread_ptr, uint32_t fread_len,
uint64_t a, uint64_t b, uint64_t c, uint64_t d,
uint64_t e, uint64_t f, uint64_t g, uint64_t h)
{
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx, hookCtx on current stack
if (NOT_IN_BOUNDS(write_ptr, write_len, memory_length) ||
NOT_IN_BOUNDS(fread_ptr, fread_len, memory_length))
return OUT_OF_BOUNDS;
if (write_len == 0 || fread_len == 0)
return TOO_SMALL;
if (write_len > 1024 || fread_len > 1024)
return TOO_BIG;
// check if there's a nul terminator on format string
bool hasnul = false;
const char* fmtptr = (const char*)(memory + fread_ptr);
for (int i = 0; i < fread_len; ++i)
if (fmtptr[i] == '\0')
{
hasnul = true;
break;
}
if (!hasnul)
return NOT_A_STRING;
//int result = snprintf(write_ptr + memory, write_len, fread_ptr + memory, a,b,c,d,e,f,g,h);
//RH NOTE: can't do this ^ because string arguments can expose non-wasm memory
// will need to parse format string ourselves, or implement our own.
return NOT_IMPLEMENTED;
}
DEFINE_HOOK_FUNCTION(
int64_t,
str_concat,
uint32_t write_ptr, uint32_t write_len,
uint32_t read_ptr, uint32_t read_len,
uint64_t operand, uint32_t operand_type)
{
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx, hookCtx on current stack
if (NOT_IN_BOUNDS(write_ptr, write_len, memory_length) ||
NOT_IN_BOUNDS(read_ptr, read_len, memory_length))
return OUT_OF_BOUNDS;
if (write_len > 1024 || read_len > 1024)
return TOO_BIG;
if (write_len == 0 || read_len == 0)
return TOO_SMALL;
if (write_len < read_len)
return TOO_SMALL;
return NOT_IMPLEMENTED;
}