aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-04-15 12:36:20 +0200
committerDmitry Vyukov <dvyukov@google.com>2024-04-15 13:23:33 +0000
commit80ce88419762e4342971463033802fea7cdb2973 (patch)
treee522a76cfc92dfe1c31470f2993923737d641d3d
parent416332e39df7236896d0d13bebcc7bb13105c0a4 (diff)
prog: use leb128 for exec encoding
Switch from uint64 to leb128 encoding for integers. This almost more than halves serialized size: - exec sizes: 10%:2160 50%:4792 90%:14288 + exec sizes: 10%:597 50%:1438 90%:7145 and makes it smaller than the text serialization: text sizes: 10%:837 50%:1591 90%:10156
-rw-r--r--executor/executor.cc64
-rw-r--r--prog/decodeexec.go14
-rw-r--r--prog/encodingexec.go5
-rw-r--r--prog/encodingexec_test.go121
4 files changed, 120 insertions, 84 deletions
diff --git a/executor/executor.cc b/executor/executor.cc
index 267fac857..84a8e0d43 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -216,7 +216,7 @@ static int running;
uint32 completed;
bool is_kernel_64_bit = true;
-static char* input_data;
+static uint8* input_data;
// Checksum kinds.
static const uint64 arg_csum_inet = 0;
@@ -260,7 +260,7 @@ struct thread_t {
bool created;
event_t ready;
event_t done;
- uint64* copyout_pos;
+ uint8* copyout_pos;
uint64 copyout_index;
bool executing;
int call_index;
@@ -368,7 +368,7 @@ struct feature_t {
void (*setup)();
};
-static thread_t* schedule_call(int call_index, int call_num, uint64 copyout_index, uint64 num_args, uint64* args, uint64* pos, call_props_t call_props);
+static thread_t* schedule_call(int call_index, int call_num, uint64 copyout_index, uint64 num_args, uint64* args, uint8* pos, call_props_t call_props);
static void handle_completion(thread_t* th);
static void copyout_call_results(thread_t* th);
static void write_call_output(thread_t* th, bool finished);
@@ -377,10 +377,10 @@ static void execute_call(thread_t* th);
static void thread_create(thread_t* th, int id, bool need_coverage);
static void thread_mmap_cover(thread_t* th);
static void* worker_thread(void* arg);
-static uint64 read_input(uint64** input_posp, bool peek = false);
-static uint64 read_arg(uint64** input_posp);
-static uint64 read_const_arg(uint64** input_posp, uint64* size_p, uint64* bf, uint64* bf_off_p, uint64* bf_len_p);
-static uint64 read_result(uint64** input_posp);
+static uint64 read_input(uint8** input_posp, bool peek = false);
+static uint64 read_arg(uint8** input_posp);
+static uint64 read_const_arg(uint8** input_posp, uint64* size_p, uint64* bf, uint64* bf_off_p, uint64* bf_len_p);
+static uint64 read_result(uint8** input_posp);
static uint64 swap(uint64 v, uint64 size, uint64 bf);
static void copyin(char* addr, uint64 val, uint64 size, uint64 bf, uint64 bf_off, uint64 bf_len);
static bool copyout(char* addr, uint64 size, uint64* res);
@@ -459,7 +459,7 @@ int main(int argc, char** argv)
#endif
if (mmap_out == MAP_FAILED)
fail("mmap of input file failed");
- input_data = static_cast<char*>(mmap_out);
+ input_data = static_cast<uint8*>(mmap_out);
#if SYZ_EXECUTOR_USES_SHMEM
mmap_output(kInitialOutput);
@@ -742,7 +742,7 @@ void execute_one()
write_output(0); // Number of executed syscalls (updated later).
#endif // if SYZ_EXECUTOR_USES_SHMEM
uint64 start = current_time_ms();
- uint64* input_pos = (uint64*)input_data;
+ uint8* input_pos = input_data;
if (cover_collection_required()) {
if (!flag_threaded)
@@ -782,10 +782,11 @@ void execute_one()
case arg_data: {
uint64 size = read_input(&input_pos);
size &= ~(1ull << 63); // readable flag
+ uint64 padded = (size + 7) & ~7;
+ if (input_pos + padded > input_data + kMaxInput)
+ fail("data arg overflow");
NONFAILING(memcpy(addr, input_pos, size));
- // Read out the data.
- for (uint64 i = 0; i < (size + 7) / 8; i++)
- read_input(&input_pos);
+ input_pos += padded;
break;
}
case arg_csum: {
@@ -950,7 +951,7 @@ void execute_one()
}
}
-thread_t* schedule_call(int call_index, int call_num, uint64 copyout_index, uint64 num_args, uint64* args, uint64* pos, call_props_t call_props)
+thread_t* schedule_call(int call_index, int call_num, uint64 copyout_index, uint64 num_args, uint64* args, uint8* pos, call_props_t call_props)
{
// Find a spare thread to execute the call.
int i = 0;
@@ -1421,7 +1422,7 @@ bool copyout(char* addr, uint64 size, uint64* res)
});
}
-uint64 read_arg(uint64** input_posp)
+uint64 read_arg(uint8** input_posp)
{
uint64 typ = read_input(input_posp);
switch (typ) {
@@ -1464,7 +1465,7 @@ uint64 swap(uint64 v, uint64 size, uint64 bf)
}
}
-uint64 read_const_arg(uint64** input_posp, uint64* size_p, uint64* bf_p, uint64* bf_off_p, uint64* bf_len_p)
+uint64 read_const_arg(uint8** input_posp, uint64* size_p, uint64* bf_p, uint64* bf_off_p, uint64* bf_len_p)
{
uint64 meta = read_input(input_posp);
uint64 val = read_input(input_posp);
@@ -1478,7 +1479,7 @@ uint64 read_const_arg(uint64** input_posp, uint64* size_p, uint64* bf_p, uint64*
return val;
}
-uint64 read_result(uint64** input_posp)
+uint64 read_result(uint8** input_posp)
{
uint64 idx = read_input(input_posp);
uint64 op_div = read_input(input_posp);
@@ -1495,14 +1496,33 @@ uint64 read_result(uint64** input_posp)
return arg;
}
-uint64 read_input(uint64** input_posp, bool peek)
+uint64 read_input(uint8** input_posp, bool peek)
{
- uint64* input_pos = *input_posp;
- if ((char*)input_pos >= input_data + kMaxInput)
- failmsg("input command overflows input", "pos=%p: [%p:%p)", input_pos, input_data, input_data + kMaxInput);
+ uint64 v = 0;
+ unsigned shift = 0;
+ uint8* input_pos = *input_posp;
+ for (int i = 0;; i++, shift += 7) {
+ const int maxLen = 10;
+ if (i == maxLen)
+ failmsg("varint overflow", "pos=%zu", *input_posp - input_data);
+ if (input_pos >= input_data + kMaxInput)
+ failmsg("input command overflows input", "pos=%p: [%p:%p)",
+ input_pos, input_data, input_data + kMaxInput);
+ uint8 b = *input_pos++;
+ v |= uint64(b & 0x7f) << shift;
+ if (b < 0x80) {
+ if (i == maxLen - 1 && b > 1)
+ failmsg("varint overflow", "pos=%zu", *input_posp - input_data);
+ break;
+ }
+ }
+ if (v & 1)
+ v = ~(v >> 1);
+ else
+ v = v >> 1;
if (!peek)
- *input_posp = input_pos + 1;
- return *input_pos;
+ *input_posp = input_pos;
+ return v;
}
#if SYZ_EXECUTOR_USES_SHMEM
diff --git a/prog/decodeexec.go b/prog/decodeexec.go
index db89aa82e..4574ef845 100644
--- a/prog/decodeexec.go
+++ b/prog/decodeexec.go
@@ -4,6 +4,7 @@
package prog
import (
+ "encoding/binary"
"fmt"
"reflect"
)
@@ -218,15 +219,16 @@ func (dec *execDecoder) readArg() ExecArg {
}
func (dec *execDecoder) read() uint64 {
- if len(dec.data) < 8 {
- dec.setErr(fmt.Errorf("exec program overflow"))
- }
if dec.err != nil {
return 0
}
- v := HostEndian.Uint64(dec.data)
- dec.data = dec.data[8:]
- return v
+ v, n := binary.Varint(dec.data)
+ if n <= 0 {
+ dec.setErr(fmt.Errorf("exec program overflow"))
+ return 0
+ }
+ dec.data = dec.data[n:]
+ return uint64(v)
}
func (dec *execDecoder) readBlob(size uint64) []byte {
diff --git a/prog/encodingexec.go b/prog/encodingexec.go
index 44a49fc58..2c13d452c 100644
--- a/prog/encodingexec.go
+++ b/prog/encodingexec.go
@@ -20,6 +20,7 @@
package prog
import (
+ "encoding/binary"
"errors"
"fmt"
"reflect"
@@ -251,8 +252,8 @@ func (w *execContext) write(v uint64) {
w.eof = true
return
}
- HostEndian.PutUint64(w.buf, v)
- w.buf = w.buf[8:]
+ n := binary.PutVarint(w.buf, int64(v))
+ w.buf = w.buf[n:]
}
func (w *execContext) writeArg(arg Arg) {
diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go
index 879aed893..2a8ce30b3 100644
--- a/prog/encodingexec_test.go
+++ b/prog/encodingexec_test.go
@@ -9,12 +9,16 @@ import (
"fmt"
"reflect"
"testing"
+
+ "github.com/bsm/histogram/v3"
)
func TestSerializeForExecRandom(t *testing.T) {
target, rs, iters := initTest(t)
ct := target.DefaultChoiceTable()
buf := make([]byte, ExecBufferSize)
+ execSizes := histogram.New(1000)
+ textSizes := histogram.New(1000)
for i := 0; i < iters; i++ {
p := target.Generate(rs, 10, ct)
n, err := p.SerializeForExec(buf)
@@ -25,7 +29,13 @@ func TestSerializeForExecRandom(t *testing.T) {
if err != nil {
t.Fatal(err)
}
+ execSizes.Add(float64(n))
+ textSizes.Add(float64(len(p.Serialize())))
}
+ t.Logf("exec sizes: 10%%:%v 50%%:%v 90%%:%v",
+ int(execSizes.Quantile(0.1)), int(execSizes.Quantile(0.5)), int(execSizes.Quantile(0.9)))
+ t.Logf("text sizes: 10%%:%v 50%%:%v 90%%:%v",
+ int(textSizes.Quantile(0.1)), int(textSizes.Quantile(0.5)), int(textSizes.Quantile(0.9)))
}
// nolint: funlen
@@ -42,26 +52,14 @@ func TestSerializeForExec(t *testing.T) {
}
return uint64(c.ID)
}
- letoh64 := func(v uint64) uint64 {
- buf := make([]byte, 8)
- buf[0] = byte(v >> 0)
- buf[1] = byte(v >> 8)
- buf[2] = byte(v >> 16)
- buf[3] = byte(v >> 24)
- buf[4] = byte(v >> 32)
- buf[5] = byte(v >> 40)
- buf[6] = byte(v >> 48)
- buf[7] = byte(v >> 56)
- return HostEndian.Uint64(buf)
- }
tests := []struct {
prog string
- serialized []uint64
+ serialized []any
decoded *ExecProg
}{
{
"test()",
- []uint64{
+ []any{
callID("test"), ExecNoCopyout, 0,
execInstrEOF,
},
@@ -76,7 +74,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$int(0x1, 0x2, 0x3, 0x4, 0x5)",
- []uint64{
+ []any{
callID("test$int"), ExecNoCopyout, 5,
execArgConst, 8, 1,
execArgConst, 1, 2,
@@ -89,7 +87,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$align0(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 2, 1,
execInstrCopyin, dataOffset + 4, execArgConst, 4, 2,
execInstrCopyin, dataOffset + 8, execArgConst, 1, 3,
@@ -102,7 +100,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$align1(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 2, 1,
execInstrCopyin, dataOffset + 2, execArgConst, 4, 2,
execInstrCopyin, dataOffset + 6, execArgConst, 1, 3,
@@ -115,7 +113,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$align2(&(0x7f0000000000)={0x42, {[0x43]}, {[0x44]}})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43,
execInstrCopyin, dataOffset + 4, execArgConst, 2, 0x44,
@@ -126,7 +124,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$align3(&(0x7f0000000000)={0x42, {0x43}, {0x44}})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
execInstrCopyin, dataOffset + 1, execArgConst, 1, 0x43,
execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44,
@@ -137,7 +135,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$align4(&(0x7f0000000000)={{0x42, 0x43}, 0x44})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43,
execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44,
@@ -148,7 +146,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$align5(&(0x7f0000000000)={{0x42, []}, {0x43, [0x44, 0x45, 0x46]}, 0x47})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 8, 0x42,
execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x43,
execInstrCopyin, dataOffset + 16, execArgConst, 2, 0x44,
@@ -162,7 +160,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$align6(&(0x7f0000000000)={0x42, [0x43]})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
execInstrCopyin, dataOffset + 4, execArgConst, 4, 0x43,
callID("test$align6"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
@@ -172,7 +170,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$union0(&(0x7f0000000000)={0x1, @f2=0x2})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 8, 1,
execInstrCopyin, dataOffset + 8, execArgConst, 1, 2,
callID("test$union0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
@@ -182,7 +180,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$union1(&(0x7f0000000000)={@f1=0x42, 0x43})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42,
execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x43,
callID("test$union1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
@@ -192,7 +190,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$union2(&(0x7f0000000000)={@f1=0x42, 0x43})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42,
execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x43,
callID("test$union2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
@@ -202,7 +200,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$array0(&(0x7f0000000000)={0x1, [@f0=0x2, @f1=0x3], 0x4})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 1, 1,
execInstrCopyin, dataOffset + 1, execArgConst, 2, 2,
execInstrCopyin, dataOffset + 3, execArgConst, 8, 3,
@@ -214,9 +212,9 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$array1(&(0x7f0000000000)={0x42, \"0102030405\"})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
- execInstrCopyin, dataOffset + 1, execArgData, 5, letoh64(0x0504030201),
+ execInstrCopyin, dataOffset + 1, execArgData, 5, []byte{0x01, 0x02, 0x03, 0x04, 0x05},
callID("test$array1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
},
@@ -224,9 +222,14 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$array2(&(0x7f0000000000)={0x42, \"aaaaaaaabbbbbbbbccccccccdddddddd\", 0x43})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42,
- execInstrCopyin, dataOffset + 2, execArgData, 16, letoh64(0xbbbbbbbbaaaaaaaa), letoh64(0xddddddddcccccccc),
+ execInstrCopyin, dataOffset + 2, execArgData, 16, []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xbb, 0xbb, 0xbb, 0xbb,
+ 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xdd, 0xdd, 0xdd, 0xdd,
+ },
execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x43,
callID("test$array2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
@@ -235,7 +238,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$end0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
execInstrCopyin, dataOffset + 1, execArgConst, 2 | 1<<8, 0x42,
execInstrCopyin, dataOffset + 3, execArgConst, 4 | 1<<8, 0x42,
@@ -247,7 +250,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$end1(&(0x7f0000000000)={0xe, 0x42, 0x1})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 2 | 1<<8, 0xe,
execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x42,
execInstrCopyin, dataOffset + 6, execArgConst, 8 | 1<<8, 0x1,
@@ -258,7 +261,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$bf0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 2 | 0<<16 | 10<<24, 0x42,
execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x42,
execInstrCopyin, dataOffset + 16, execArgConst, 2 | 0<<16 | 5<<24, 0x42,
@@ -358,7 +361,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$bf1(&(0x7f0000000000)={{0x42, 0x42, 0x42}, 0x42})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 4 | 0<<16 | 10<<24, 0x42,
execInstrCopyin, dataOffset + 0, execArgConst, 4 | 10<<16 | 10<<24, 0x42,
execInstrCopyin, dataOffset + 0, execArgConst, 4 | 20<<16 | 10<<24, 0x42,
@@ -370,7 +373,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$res1(0xffff)",
- []uint64{
+ []any{
callID("test$res1"), ExecNoCopyout, 1, execArgConst, 4, 0xffff,
execInstrEOF,
},
@@ -378,7 +381,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$opt3(0x0)",
- []uint64{
+ []any{
callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8 | 4<<32, 0x64,
execInstrEOF,
},
@@ -387,7 +390,7 @@ func TestSerializeForExec(t *testing.T) {
{
// Special value that translates to 0 for all procs.
"test$opt3(0xffffffffffffffff)",
- []uint64{
+ []any{
callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8, 0,
execInstrEOF,
},
@@ -396,7 +399,7 @@ func TestSerializeForExec(t *testing.T) {
{
// NULL pointer must be encoded os 0.
"test$opt1(0x0)",
- []uint64{
+ []any{
callID("test$opt1"), ExecNoCopyout, 1, execArgConst, 8, 0,
execInstrEOF,
},
@@ -404,7 +407,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$align7(&(0x7f0000000000)={{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}, 0x42})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 1 | 0<<16 | 1<<24, 0x1,
execInstrCopyin, dataOffset + 0, execArgConst, 1 | 1<<16 | 1<<24, 0x2,
execInstrCopyin, dataOffset + 0, execArgConst, 1 | 2<<16 | 1<<24, 0x3,
@@ -419,7 +422,7 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$excessive_fields1(0x0)",
- []uint64{
+ []any{
callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0x0,
execInstrEOF,
},
@@ -427,28 +430,28 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$excessive_fields1(0xffffffffffffffff)",
- []uint64{
- callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0xffffffffffffffff,
+ []any{
+ callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, uint64(0xffffffffffffffff),
execInstrEOF,
},
nil,
},
{
"test$excessive_fields1(0xfffffffffffffffe)",
- []uint64{
- callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0x9999999999999999,
+ []any{
+ callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, uint64(0x9999999999999999),
execInstrEOF,
},
nil,
},
{
"test$csum_ipv4_tcp(&(0x7f0000000000)={{0x0, 0x1, 0x2}, {{0x0}, \"ab\"}})",
- []uint64{
+ []any{
execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x0,
execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x1,
execInstrCopyin, dataOffset + 6, execArgConst, 4 | 1<<8, 0x2,
execInstrCopyin, dataOffset + 10, execArgConst, 2, 0x0,
- execInstrCopyin, dataOffset + 12, execArgData, 1, letoh64(0xab),
+ execInstrCopyin, dataOffset + 12, execArgData, 1, []byte{0xab},
execInstrCopyin, dataOffset + 10, execArgCsum, 2, ExecArgCsumInet, 5,
ExecArgCsumChunkData, dataOffset + 2, 4,
ExecArgCsumChunkData, dataOffset + 6, 4,
@@ -467,7 +470,7 @@ func TestSerializeForExec(t *testing.T) {
test() (fail_nth: 4)
test() (async, rerun: 10)
`,
- []uint64{
+ []any{
execInstrSetProps, 3, 0, 0,
callID("test"), ExecNoCopyout, 0,
execInstrSetProps, 4, 0, 0,
@@ -510,14 +513,24 @@ test() (async, rerun: 10)
if err != nil {
t.Fatalf("failed to serialize: %v", err)
}
- w := new(bytes.Buffer)
- binary.Write(w, HostEndian, test.serialized)
+ var want []byte
+ for _, e := range test.serialized {
+ switch elem := e.(type) {
+ case uint64:
+ want = binary.AppendVarint(want, int64(elem))
+ case int:
+ want = binary.AppendVarint(want, int64(elem))
+ case []byte:
+ want = append(want, elem...)
+ want = append(want, make([]byte, ((len(elem)+7) & ^7)-len(elem))...)
+ default:
+ t.Fatalf("unexpected elem type %T %#v", e, e)
+ }
+ }
data := buf[:n]
- if !bytes.Equal(data, w.Bytes()) {
- got := make([]uint64, len(data)/8)
- binary.Read(bytes.NewReader(data), HostEndian, &got)
+ if !bytes.Equal(data, want) {
t.Logf("want: %v", test.serialized)
- t.Logf("got: %v", got)
+ t.Logf("got: %q", data)
t.Fatalf("mismatch")
}
decoded, err := target.DeserializeExec(data)
@@ -574,7 +587,7 @@ func TestSerializeForExecOverflow(t *testing.T) {
overflow: true,
gen: func(w *bytes.Buffer) {
fmt.Fprintf(w, "r0 = test$res0()\n")
- for i := 0; i < 59e3; i++ {
+ for i := 0; i < 4e5; i++ {
fmt.Fprintf(w, "test$res1(r0)\n")
}
},