/*
 * DF-0732 leak checker — definitively detects REAL heap residue in the
 * returned ACL list, distinguishing it from valid adder MACs.
 *
 * Real heap residue (with use_malloc_pattern=1) contains the slab
 * WEIRD_ADDR pattern 0xdeadc0de (sys/kern/kern_slaballoc.c).  Valid adder
 * MACs are de:ad:be:XX:XX:XX.  This checker scans every returned 6-byte
 * slot and classifies it:
 *   - MAC_ADDER  : de ad be ?? ?? ??   (valid adder entry)
 *   - MAC_SEED   : aa bb cc dd ?? ??   (valid pre-seeded entry)
 *   - WEIRD      : contains de ad c0 de (slab freed-object residue = LEAK)
 *   - ZERO       : all six bytes 0x00   (M_ZERO'd, never written = safe)
 *   - OTHER      : anything else        (suspicious — print hex)
 *
 * BUGGY module: expect WEIRD hits (heap residue leaked).
 * FIXED module: expect ZERO WEIRD hits (M_ZERO + lock-before-read).
 *
 * Build: cc -O2 -pthread -o leakcheck leakcheck.c
 * Run:   ./leakcheck [iterations]
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>

struct df0732_list_req { void *buf; size_t len; size_t *ret_len; };
#define DF0732_IOCTL_LIST _IOW('D', 1, struct df0732_list_req)

#define BUF_ENTRIES 8192
#define BUF_SIZE    (BUF_ENTRIES * 6)

static volatile int stop_flag;
static int g_fd;
static volatile unsigned long weird_hits, zero_slots, adder_slots, other_hits;
static volatile unsigned long total_calls;

static void
classify(const unsigned char *buf, size_t bytes)
{
	size_t slots = bytes / 6, i;
	for (i = 0; i < slots; i++) {
		const unsigned char *p = buf + i * 6;
		if (p[0]==0xde && p[1]==0xad && p[2]==0xbe) {
			__sync_fetch_and_add(&adder_slots, 1);
		} else if (p[0]==0xaa && p[1]==0xbb && p[2]==0xcc && p[3]==0xdd) {
			__sync_fetch_and_add(&adder_slots, 1); /* seed */
		} else if ((p[0]|p[1]|p[2]|p[3]|p[4]|p[5]) == 0) {
			__sync_fetch_and_add(&zero_slots, 1);
		} else if (p[0]==0xde && p[1]==0xad && p[2]==0xc0 && p[3]==0xde) {
			__sync_fetch_and_add(&weird_hits, 1);   /* WEIRD_ADDR = LEAK */
		} else if (p[0]==0xc0 && p[1]==0xde && p[2]==0xad && p[3]==0xbe) {
			__sync_fetch_and_add(&weird_hits, 1);   /* shifted WEIRD_ADDR */
		} else {
			__sync_fetch_and_add(&other_hits, 1);
		}
	}
}

static void *
worker(void *arg)
{
	unsigned long iters = (unsigned long)arg;
	unsigned long n = 0;
	unsigned char *buf = malloc(BUF_SIZE);
	while (!stop_flag && buf) {
		struct df0732_list_req req;
		size_t ret_len = 0;
		req.buf = buf; req.len = BUF_SIZE; req.ret_len = &ret_len;
		memset(buf, 0x5a, BUF_SIZE);   /* distinct pre-fill */
		if (ioctl(g_fd, DF0732_IOCTL_LIST, &req) == 0) {
			if (ret_len > BUF_SIZE) ret_len = BUF_SIZE;
			classify(buf, ret_len);
		}
		__sync_fetch_and_add(&total_calls, 1);
		if (++n >= iters) { stop_flag = 1; break; }
	}
	free(buf);
	return NULL;
}

int
main(int argc, char **argv)
{
	unsigned long iters = (argc > 1) ? strtoul(argv[1], NULL, 0) : 100000UL;
	int nthreads = (argc > 2) ? atoi(argv[2]) : 4;
	pthread_t *tids;
	int i;

	g_fd = open("/dev/df0732", O_RDWR);
	if (g_fd < 0) { perror("open /dev/df0732"); return 1; }
	tids = calloc(nthreads, sizeof(*tids));
	for (i = 0; i < nthreads; i++)
		pthread_create(&tids[i], NULL, worker, (void *)(iters/nthreads+1));
	for (i = 0; i < nthreads; i++)
		pthread_join(tids[i], NULL);

	printf("leakcheck: %lu LIST ioctls\n", total_calls);
	printf("  adder/seed MAC slots : %lu\n", adder_slots);
	printf("  ZERO (M_ZERO) slots  : %lu\n", zero_slots);
	printf("  WEIRD_ADDR residue   : %lu   %s\n", weird_hits,
		weird_hits > 0 ? "<== HEAP RESIDUE LEAK" : "(none — leak eliminated)");
	printf("  OTHER (suspicious)   : %lu\n", other_hits);
	close(g_fd);
	return (weird_hits > 0) ? 1 : 0;
}
