github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/executor/test.h (about)

     1  // Copyright 2017 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  #if GOOS_linux && (GOARCH_amd64 || GOARCH_ppc64 || GOARCH_ppc64le || GOARCH_arm64)
     5  #include "test_linux.h"
     6  #endif
     7  
     8  #include <algorithm>
     9  #include <fcntl.h>
    10  #include <sys/stat.h>
    11  #include <unistd.h>
    12  
    13  static int test_copyin()
    14  {
    15  	static uint16 buf[3];
    16  	STORE_BY_BITMASK(uint16, htole16, &buf[1], 0x1234, 0, 16);
    17  	unsigned char x[sizeof(buf)];
    18  	memcpy(x, buf, sizeof(x));
    19  	if (x[0] != 0 || x[1] != 0 ||
    20  	    x[2] != 0x34 || x[3] != 0x12 ||
    21  	    x[4] != 0 || x[5] != 0) {
    22  		printf("bad result of STORE_BY_BITMASK(le16, 0x1234, 0, 16): %x %x %x %x %x %x\n",
    23  		       x[0], x[1], x[2], x[3], x[4], x[5]);
    24  		return 1;
    25  	}
    26  	STORE_BY_BITMASK(uint16, htole16, &buf[1], 0x555a, 5, 4);
    27  	memcpy(x, buf, sizeof(x));
    28  	if (x[0] != 0 || x[1] != 0 ||
    29  	    x[2] != 0x54 || x[3] != 0x13 ||
    30  	    x[4] != 0 || x[5] != 0) {
    31  		printf("bad result of STORE_BY_BITMASK(le16, 0x555a, 5, 4): %x %x %x %x %x %x\n",
    32  		       x[0], x[1], x[2], x[3], x[4], x[5]);
    33  		return 1;
    34  	}
    35  	STORE_BY_BITMASK(uint16, htobe16, &buf[1], 0x4567, 13, 3);
    36  	memcpy(x, buf, sizeof(x));
    37  	if (x[0] != 0 || x[1] != 0 ||
    38  	    x[2] != 0xf4 || x[3] != 0x13 ||
    39  	    x[4] != 0 || x[5] != 0) {
    40  		printf("bad result of STORE_BY_BITMASK(be16, 0x4567, 13, 3): %x %x %x %x %x %x\n",
    41  		       x[0], x[1], x[2], x[3], x[4], x[5]);
    42  		return 1;
    43  	}
    44  	return 0;
    45  }
    46  
    47  static int test_csum_inet()
    48  {
    49  	struct csum_inet_test {
    50  		const char* data;
    51  		size_t length;
    52  		uint16 csum;
    53  	};
    54  	struct csum_inet_test tests[] = {
    55  	    {// 0
    56  	     "",
    57  	     0,
    58  	     le16toh(0xffff)},
    59  	    {
    60  		// 1
    61  		"\x00",
    62  		1,
    63  		le16toh(0xffff),
    64  	    },
    65  	    {
    66  		// 2
    67  		"\x00\x00",
    68  		2,
    69  		le16toh(0xffff),
    70  	    },
    71  	    {
    72  		// 3
    73  		"\x00\x00\xff\xff",
    74  		4,
    75  		le16toh(0x0000),
    76  	    },
    77  	    {
    78  		// 4
    79  		"\xfc",
    80  		1,
    81  		le16toh(0xff03),
    82  	    },
    83  	    {
    84  		// 5
    85  		"\xfc\x12",
    86  		2,
    87  		le16toh(0xed03),
    88  	    },
    89  	    {
    90  		// 6
    91  		"\xfc\x12\x3e",
    92  		3,
    93  		le16toh(0xecc5),
    94  	    },
    95  	    {
    96  		// 7
    97  		"\xfc\x12\x3e\x00\xc5\xec",
    98  		6,
    99  		le16toh(0x0000),
   100  	    },
   101  	    {
   102  		// 8
   103  		"\x42\x00\x00\x43\x44\x00\x00\x00\x45\x00\x00\x00\xba\xaa\xbb\xcc\xdd",
   104  		17,
   105  		le16toh(0x43e1),
   106  	    },
   107  	    {
   108  		// 9
   109  		"\x42\x00\x00\x43\x44\x00\x00\x00\x45\x00\x00\x00\xba\xaa\xbb\xcc\xdd\x00",
   110  		18,
   111  		le16toh(0x43e1),
   112  	    },
   113  	    {
   114  		// 10
   115  		"\x00\x00\x42\x00\x00\x43\x44\x00\x00\x00\x45\x00\x00\x00\xba\xaa\xbb\xcc\xdd",
   116  		19,
   117  		le16toh(0x43e1),
   118  	    },
   119  	    {
   120  		// 11
   121  		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\xab\xcd",
   122  		15,
   123  		le16toh(0x5032),
   124  	    },
   125  	    {
   126  		// 12
   127  		"\x00\x00\x12\x34\x56\x78",
   128  		6,
   129  		le16toh(0x5397),
   130  	    },
   131  	    {
   132  		// 13
   133  		"\x00\x00\x12\x34\x00\x00\x56\x78\x00\x06\x00\x04\xab\xcd",
   134  		14,
   135  		le16toh(0x7beb),
   136  	    },
   137  	    {
   138  		// 14
   139  		"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\xab\xcd",
   140  		44,
   141  		le16toh(0x2854),
   142  	    },
   143  	    {
   144  		// 15
   145  		"\x00\x00\x12\x34\x00\x00\x56\x78\x00\x11\x00\x04\xab\xcd",
   146  		14,
   147  		le16toh(0x70eb),
   148  	    },
   149  	    {
   150  		// 16
   151  		"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00\x00\x00\x00\x04\x00\x00\x00\x11\x00\x00\xab\xcd",
   152  		44,
   153  		le16toh(0x1d54),
   154  	    },
   155  	    {
   156  		// 17
   157  		"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00\x00\x00\x00\x04\x00\x00\x00\x3a\x00\x00\xab\xcd",
   158  		44,
   159  		le16toh(0xf453),
   160  	    }};
   161  
   162  	for (unsigned i = 0; i < ARRAY_SIZE(tests); i++) {
   163  		struct csum_inet csum;
   164  		csum_inet_init(&csum);
   165  		csum_inet_update(&csum, (const uint8*)tests[i].data, tests[i].length);
   166  		if (csum_inet_digest(&csum) != tests[i].csum) {
   167  			fprintf(stderr, "bad checksum in test #%u, want: %hx, got: %hx\n", i, tests[i].csum, csum_inet_digest(&csum));
   168  			return 1;
   169  		}
   170  	}
   171  
   172  	return 0;
   173  }
   174  
   175  static int rand_int_range(int start, int end)
   176  {
   177  	return rand() % (end + 1 - start) + start;
   178  }
   179  
   180  static int test_csum_inet_acc()
   181  {
   182  	uint8 buffer[128];
   183  
   184  	for (int test = 0; test < 256; test++) {
   185  		int size = rand_int_range(1, 128);
   186  		int step = rand_int_range(1, 8) * 2;
   187  
   188  		for (int i = 0; i < size; i++)
   189  			buffer[i] = rand_int_range(0, 255);
   190  
   191  		struct csum_inet csum_acc;
   192  		csum_inet_init(&csum_acc);
   193  
   194  		for (int i = 0; i < size / step; i++)
   195  			csum_inet_update(&csum_acc, &buffer[i * step], step);
   196  		if (size % step != 0)
   197  			csum_inet_update(&csum_acc, &buffer[size - size % step], size % step);
   198  
   199  		struct csum_inet csum;
   200  		csum_inet_init(&csum);
   201  		csum_inet_update(&csum, &buffer[0], size);
   202  
   203  		if (csum_inet_digest(&csum_acc) != csum_inet_digest(&csum))
   204  			return 1;
   205  	}
   206  	return 0;
   207  }
   208  
   209  static int test_cover_filter()
   210  {
   211  	CoverFilter filter;
   212  	CoverFilter child(filter.FD());
   213  
   214  	std::vector<uint64> pcs = {
   215  	    100,
   216  	    111,
   217  	    200,
   218  	    (1 << 20) - 1,
   219  	    1 << 20,
   220  	    (1 << 30) - 1,
   221  	    100ull << 30,
   222  	    (100ull << 30) + 100,
   223  	    200ull << 30,
   224  	    (1ull << 62) + 100,
   225  	};
   226  
   227  	// These we don't insert, but they are also present due to truncation of low 3 bits.
   228  	std::vector<uint64> also_contain = {
   229  	    96,
   230  	    103,
   231  	    104,
   232  	    207,
   233  	    (1 << 20) - 7,
   234  	    (1 << 20) + 7,
   235  	    (1ull << 62) + 96,
   236  	    (1ull << 62) + 103,
   237  	};
   238  
   239  	std::vector<uint64> dont_contain = {
   240  	    0,
   241  	    1,
   242  	    95,
   243  	    112,
   244  	    199,
   245  	    208,
   246  	    100 << 10,
   247  	    (1 << 20) - 9,
   248  	    (1 << 20) + 8,
   249  	    (2ull << 30) - 1,
   250  	    2ull << 30,
   251  	    (2ull << 30) + 1,
   252  	    (100ull << 30) + 108,
   253  	    150ull << 30,
   254  	    1ull << 40,
   255  	    1ull << 63,
   256  	    ~0ull,
   257  	};
   258  
   259  	int ret = 0;
   260  	for (auto pc : pcs)
   261  		filter.Insert(pc);
   262  	pcs.insert(pcs.end(), also_contain.begin(), also_contain.end());
   263  	for (auto pc : pcs) {
   264  		if (!filter.Contains(pc) || !child.Contains(pc)) {
   265  			printf("filter doesn't contain %llu (0x%llx)\n", pc, pc);
   266  			ret = 1;
   267  		}
   268  	}
   269  	for (auto pc : dont_contain) {
   270  		if (filter.Contains(pc) || child.Contains(pc)) {
   271  			printf("filter contains %llu (0x%llx)\n", pc, pc);
   272  			ret = 1;
   273  		}
   274  	}
   275  	return ret;
   276  }
   277  
   278  static bool test_one_glob(const char* pattern, std::vector<std::string> want)
   279  {
   280  	std::vector<std::string> got = Glob(pattern);
   281  	std::sort(want.begin(), want.end());
   282  	std::sort(got.begin(), got.end());
   283  	if (got == want)
   284  		return true;
   285  	printf("pattern '%s', want %zu files:\n", pattern, want.size());
   286  	for (const auto& f : want)
   287  		printf("\t'%s'\n", f.c_str());
   288  	printf("got %zu files:\n", got.size());
   289  	for (const auto& f : got)
   290  		printf("\t'%s'\n", f.c_str());
   291  	return false;
   292  }
   293  
   294  static void must_mkdir(const char* dir)
   295  {
   296  	if (mkdir(dir, 0700))
   297  		failmsg("mkdir failed", "dir=%s", dir);
   298  }
   299  
   300  static void must_creat(const char* file)
   301  {
   302  	int fd = open(file, O_CREAT | O_EXCL, 0700);
   303  	if (fd == -1)
   304  		failmsg("open failed", "file=%s", file);
   305  	close(fd);
   306  }
   307  
   308  static void must_link(const char* oldpath, const char* linkpath)
   309  {
   310  	if (link(oldpath, linkpath))
   311  		failmsg("link failed", "oldpath=%s linkpath=%s", oldpath, linkpath);
   312  }
   313  
   314  static void must_symlink(const char* oldpath, const char* linkpath)
   315  {
   316  	if (symlink(oldpath, linkpath))
   317  		failmsg("symlink failed", "oldpath=%s linkpath=%s", oldpath, linkpath);
   318  }
   319  
   320  static int test_glob()
   321  {
   322  #if GOARCH_arm
   323  	// When running a 32-bit ARM binary on a 64-bit system under QEMU, readdir() fails
   324  	// with EOVERFLOW, resulting in Glob() returning 0 files.
   325  	// Tracking QEMU bug: https://gitlab.com/qemu-project/qemu/-/issues/263.
   326  	return -1;
   327  #endif
   328  	// Note: pkg/runtest.TestExecutor creates a temp dir for the test,
   329  	// so we create files in cwd and don't clean up.
   330  	if (!test_one_glob("glob/*", {}))
   331  		return 1;
   332  	must_mkdir("glob");
   333  	if (!test_one_glob("glob/*", {}))
   334  		return 1;
   335  	must_mkdir("glob/dir1");
   336  	must_creat("glob/file1");
   337  	must_mkdir("glob/dir2");
   338  	must_creat("glob/dir2/file21");
   339  	must_mkdir("glob/dir3");
   340  	must_creat("glob/dir3/file31");
   341  	must_link("glob/dir3/file31", "glob/dir3/file32");
   342  	must_symlink("file31", "glob/dir3/file33");
   343  	must_symlink("deadlink", "glob/dir3/file34");
   344  	must_symlink("../../glob", "glob/dir3/dir31");
   345  	must_mkdir("glob/dir4");
   346  	must_mkdir("glob/dir4/dir41");
   347  	must_creat("glob/dir4/dir41/file411");
   348  	must_symlink("dir4", "glob/dir5");
   349  	must_mkdir("glob/dir6");
   350  	must_mkdir("glob/dir6/dir61");
   351  	must_creat("glob/dir6/dir61/file611");
   352  	must_symlink("dir6/dir61", "glob/self");
   353  	// Directories are not includes + not recursive (yet).
   354  	if (!test_one_glob("glob/*", {
   355  					 "glob/file1",
   356  				     }))
   357  		return 1;
   358  	if (!test_one_glob("glob/*/*", {
   359  					   "glob/dir2/file21",
   360  					   "glob/dir3/file31",
   361  					   "glob/dir3/file32", // hard links are included
   362  					   "glob/self/file611", // symlinks via name "self" are included
   363  				       }))
   364  		return 1;
   365  	return 0;
   366  }
   367  
   368  static struct {
   369  	const char* name;
   370  	int (*f)();
   371  } tests[] = {
   372      {"test_copyin", test_copyin},
   373      {"test_csum_inet", test_csum_inet},
   374      {"test_csum_inet_acc", test_csum_inet_acc},
   375  #if GOOS_linux && (GOARCH_amd64 || GOARCH_ppc64 || GOARCH_ppc64le || GOARCH_arm64)
   376      {"test_kvm", test_kvm},
   377  #endif
   378  #if GOOS_linux && GOARCH_arm64
   379      {"test_syzos", test_syzos},
   380  #endif
   381      {"test_cover_filter", test_cover_filter},
   382      {"test_glob", test_glob},
   383  };
   384  
   385  static int run_tests(const char* test)
   386  {
   387  	int ret = 0;
   388  	for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
   389  		const char* name = tests[i].name;
   390  		if (test && strcmp(test, name))
   391  			continue;
   392  		printf("=== RUN  %s\n", name);
   393  		int res = tests[i].f();
   394  		ret |= res > 0;
   395  		const char* strres = res < 0 ? "SKIP" : (res > 0 ? "FAIL" : "OK");
   396  		printf("--- %-4s %s\n", strres, name);
   397  	}
   398  	return ret;
   399  }