/*
 * DF-2544 -- devclass_alloc_unit (kern/subr_bus.c:1067-1119) validates a
 * wired unit only for unit >= 0; a negative non-wildcard unit (< -1)
 * skips the table-grow branch and is returned as-is, and
 * devclass_add_device (:1141) then executes dc->devices[dev->unit] = dev
 * -- a write at a NEGATIVE array index (heap underflow), or a write near
 * NULL when dc->devices == NULL (fresh devclass).
 *
 * Rig: real device_add_child() with unit = -5 on a fresh devclass
 * (registered via a dummy driver), driven from a sysctl.
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/bus.h>
#include <sys/module.h>

static int dfv2544_go(SYSCTL_HANDLER_ARGS);

SYSCTL_PROC(_kern, OID_AUTO, dfv2544, CTLTYPE_INT | CTLFLAG_RW,
    0, 0, dfv2544_go, "I", "write 1 to trigger negative-unit device_add_child");

static device_method_t dfp44_methods[] = {
	DEVMETHOD_END
};

static driver_t dfp44_driver = {
	"dfp44",
	dfp44_methods,
	0
};

static devclass_t dfp44_devclass;

DRIVER_MODULE(dfp44, nexus, dfp44_driver, dfp44_devclass, NULL, NULL);

static int
dfv2544_go(SYSCTL_HANDLER_ARGS)
{
	int error, v = 0;
	device_t child, nexus;

	if (req->newptr != NULL) {
		error = sysctl_handle_int(oidp, &v, 0, req);
		if (error)
			return error;
		if (v != 1)
			return EINVAL;
		nexus = devclass_get_device(devclass_find("nexus"), 0);
		kprintf("dfv2544: nexus=%p, device_add_child(nexus, dfp44, -5)...\n",
		    nexus);
		child = device_add_child(nexus, "dfp44", -5);
		kprintf("dfv2544: device_add_child returned %p (expected NULL "
		    "or panic at dc->devices[-5] with devices==NULL)\n", child);
		return 0;
	}
	return sysctl_handle_int(oidp, &v, 0, req);
}
