Bug 59650

Summary: sprintf() bus errors in non-main thread with %f
Product: Base System Reporter: Adriaan de Groot <adridg>
Component: amd64Assignee: freebsd-amd64 (Nobody) <amd64>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 5.1-CURRENT   
Hardware: Any   
OS: Any   

Description Adriaan de Groot 2003-11-24 19:10:17 UTC
	The ogg123 port bus errors on an amd64 machine. This is because
	sprintf() and fprintf() do "something weird" with %f arguments
	in threads that are not the main thread of control.

How-To-Repeat: 	This program demonstrates the problem:

/* Demonstration program that shows that sprintf() doesn't
   work with double args from threads that aren't the main
   thread of control.
*/

#include <stdio.h>
#include <pthread.h>
#include <time.h>

void slipper(void *p)
{
        fprintf(stderr,"[%lx] d=%d t=%d\n",(long)pthread_self(),3,time(NULL));
	sleep(3);
	fprintf(stderr,"%f\n",22/7);
	fprintf(stderr,"%06.3f\n",0.002462390263402);
}

int main(int argc, char **argv)
{
        pthread_t tid;

	slipper(NULL);

	pthread_create(&tid,NULL,slipper,NULL);

	sleep(6);
	slipper(NULL);

	return 0;
}
						}


	Expected output is something like

[lofi@lofi]:0:~ > ./threadtest
[804c000] d=3 t=1069603991
0.000000
00.002
[804c400] d=3 t=1069603994
0.000000
00.002
[804c000] d=3 t=1069604000
0.000000
00.002

	and on 4-STABLE i386, 5-CURRENT i386, and 5-CURRENT alpha,
	that is exactly what it does. On amd64, however,

beans.ebn.kun.nl$./threadtest
[504000] d=3 t=1069604372
0.000000
00.002
[504800] d=3 t=1069604375
0.000000
Bus error (core dumped)

	Note that the "plain" %f when printing a 0 value works,
	but that sprintf() bus errors in the second call.
	Replacing 22/7 by the constant 0.002462390263402 in the 
	code causes a bus error in the first call to sprintf().

(gdb) bt
#0  0x0000000200841189 in fprintf () from /lib/libc.so.5
#1  0x000000000040086f in slipper ()
#2  0x000000020063c670 in _thread_start () from /usr/lib/libc_r.so.5
Error accessing memory address 0x7fffffeff000: Bad address.

	Possibly relevant disassembly:

0x0000000200841181 <fprintf+125>:       movaps %xmm2,0xffffffffffffffa1(%rax)
0x0000000200841185 <fprintf+129>:       movaps %xmm1,0xffffffffffffff91(%rax)
0x0000000200841189 <fprintf+133>:       movaps %xmm0,0xffffffffffffff81(%rax)
0x000000020084118d <fprintf+137>:       mov    %rsi,0xffffffffffffff40(%rbp)
0x0000000200841194 <fprintf+144>:       movl   $0x10,0xffffffffffffff10(%rbp)
0x000000020084119e <fprintf+154>:       movl   $0x30,0xffffffffffffff14(%rbp)

	(If it's gonna bus error, I'll suspect those odd constants in
	the three movaps instructions.)
Comment 1 Adriaan de Groot 2003-11-26 13:23:10 UTC
Some further debugging shows that it's not even sprintf() of va_start() 
specific, but just passing float / double arguments to a varargs function in 
a non-main thread of control triggers bus errors already:

/*
** Demonstration program that float parameters to
** varargs functions in non-main threads of
** control on amd64 does not work properly.
*/

#include <stdio.h>
#include <pthread.h>
#include <stdarg.h>


/*
** This is a varargs function to which we will attempt to pass
** a float value in the ... .
*/

int PrintF(int fd, const char *fmt, int i, ...)
{
        int ret = 2;
        fprintf(stderr,"[%lx]B %d\n",(long)pthread_self(),fd);
        return ret;
}


/*
** Demonstration function. Expected output is something like
**
** [504000]B 0
** [504000]B 1
** [504000]B 2
** [504000]B 3
**
** From the 4 calls to PrintF(). This bus errors in the third
** call when not in the main thread of control.
*/

void *threadfunc(void *p)
{
        PrintF(0,"hello",0,0);
        PrintF(1,"hello",0,6);
        PrintF(2,"hello",1,0.00028376223); /* arg4 is a float */
        PrintF(3,"hello",0.00028376223,6); /* arg3 converts to int here */
        return p;
}

int main(int argc, char **argv)
{
        pthread_t tid;

        threadfunc(NULL);
        pthread_create(&tid,NULL,threadfunc,NULL);
        sleep(4);
        threadfunc(NULL);

        return 0;
}

Now, either I'm doing something totally moronic with threads (and the ogg123 
port is too) or the argument passing is seriously broken. I might be 
compiling it wrong, though:

beans.ebn.kun.nl$gcc -o threadtest -g v.c -lc_r && ./threadtest
[504000]B 0
[504000]B 1
[504000]B 2
[504000]B 3
[504800]B 0
[504800]B 1
Bus error (core dumped)

The machine has been updated in -CURRENT since the original bug report:

FreeBSD beans.ebn.kun.nl 5.2-BETA FreeBSD 5.2-BETA #2: Sun Nov 23 19:48:43 CET 
2003     root@beans.ebn.kun.nl:/usr/obj/mnt/sys/CURRENT/src/sys/BEANS  amd64


-- 
pub  1024D/FEA2A3FE 2002-06-18 Adriaan de Groot <groot@kde.org>
            If the door is ajar, can we fill it with door-jamb?
Comment 2 John-Mark Gurney freebsd_committer freebsd_triage 2003-12-03 00:07:34 UTC
State Changed
From-To: open->closed

as per Adriaan's request close the PR, Peter has fixed this in libc_r..