Subject: kern/5494: Off-by-one error in ossaudio SNDCTL_DSP_SETFRAGMENT
To: None <gnats-bugs@gnats.netbsd.org>
From: None <nathanw@MIT.EDU>
List: netbsd-bugs
Date: 05/25/1998 11:40:17
>Number:         5494
>Category:       kern
>Synopsis:       An off-by-one error returns the wrong value after setting the right one
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon May 25 08:50:00 1998
>Last-Modified:
>Originator:     Nathan J. Williams
>Organization:
	Massachvsetts Institvte of Technology
>Release:        NetBSD-current of 1998/5/25
>Environment:
System: NetBSD road-runner.mit.edu 1.3E NetBSD 1.3E (ROAD-RUNNER) #114: Mon May 25 01:09:40 EDT 1998 nathanw@road-runner.mit.edu:/u1/usr/src/sys/arch/i386/compile/ROAD-RUNNER i386


>Description:
	The OSS_SNDCTL_DSP_SETFRAGMENT ioctl takes an integer argument
whose upper 16 bits represent the maximum number of buffers to be used
and whose lower 16 bits represent the base-2 log of the size of each
buffer block. The compat code that implements this ioctl in terms of
our audio interface sets the parameters properly, but returns a buffer
size one greater than was set.

>How-To-Repeat:
	Try to run some code that uses the OSS interface and checks
the returned parameter against the originally submitted
paramater. Watch it fail. Or, run the following code (compiled in such
a way as to trigger OSS compatibility, for example, on a Linux
system):

#include <fcntl.h>
#include <sys/soundcard.h>

#define SND_BITS 8
#define SND_BUFFERS 8

int main(void)
{
  int j,k;
  int fd,ret;

  fd = open("/dev/dsp", O_WRONLY | O_NONBLOCK);
  if (fd == -1) {
      perror("open");
      exit(1);
  }	

  j = k = SND_BITS | (SND_BUFFERS << 16);

  printf("%08x %08x\n",j,k);
  ret=ioctl(fd,SNDCTL_DSP_SETFRAGMENT,&j);
  if (ret == -1)
    perror("ioctl");
  printf("%08x %08x\n",j,k);

  close(fd);
  return 0;
}

Output: 
00080008 00080008
00080009 00080008

Kernel output (with AUDIO_DEBUG defined):
May 25 11:35:08 road-runner /netbsd: oss_audio: SETFRAGMENT blksize=256, hiwat=8

Note that 2**9 != 256.

>Fix:

	Fix the off-by-one error in the loop that computes
ln(blocksize). 

*** ossaudio.c.orig	Mon May 25 11:26:12 1998
--- ossaudio.c	Mon May 25 11:26:15 1998
***************
*** 322,328 ****
  		if (error)
  			return error;
  		u = tmpinfo.blocksize;
! 		for(idat = 0; u; idat++, u >>= 1)
  			;
  		idat |= (tmpinfo.hiwat & 0x7fff) << 16;
  		error = copyout(&idat, SCARG(uap, data), sizeof idat);
--- 322,328 ----
  		if (error)
  			return error;
  		u = tmpinfo.blocksize;
! 		for(idat = 0; u>1; idat++, u >>= 1)
  			;
  		idat |= (tmpinfo.hiwat & 0x7fff) << 16;
  		error = copyout(&idat, SCARG(uap, data), sizeof idat);

>Audit-Trail:
>Unformatted: