From oleg@core.zp.ua  Sun Dec 19 14:47:54 2004
Return-Path: <oleg@core.zp.ua>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id CE01216A4CE
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 19 Dec 2004 14:47:54 +0000 (GMT)
Received: from core.zp.ua (core.zp.ua [193.108.112.7])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 5C43043D48
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 19 Dec 2004 14:47:53 +0000 (GMT)
	(envelope-from oleg@core.zp.ua)
Received: from core.zp.ua (oleg@localhost [127.0.0.1])
	by core.zp.ua with ESMTP id iBJElonT025667
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 19 Dec 2004 16:47:50 +0200 (EET)
	(envelope-from oleg@core.zp.ua)
Received: (from oleg@localhost)
	by core.zp.ua  id iBJEln8f025666;
	 Sun, 19 Dec 2004 16:47:49 +0200 (EET)
Message-Id: <200412191447.iBJEln8f025666@core.zp.ua>
Date: Sun, 19 Dec 2004 16:47:49 +0200 (EET)
From: "Oleg V. Nauman" <oleg@reis.zp.ua>
Reply-To: "Oleg V. Nauman" <oleg@reis.zp.ua>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [patch] dd(1) has not async signal safe interrupt handlers
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         75258
>Category:       bin
>Synopsis:       [patch] dd(1) has not async signal safe interrupt handlers
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Dec 19 14:50:21 GMT 2004
>Closed-Date:    Fri May 10 18:44:40 UTC 2013
>Last-Modified:  Fri May 10 18:50:00 UTC 2013
>Originator:     Oleg V. Nauman
>Release:        FreeBSD 5.3-STABLE i386
>Organization:
ReIS LLC
>Environment:
System: FreeBSD core.zp.ua 5.3-STABLE FreeBSD 5.3-STABLE #16: Fri Dec 17 22:26:44 EET 2004 root@core.zp.ua:/usr/src/sys/i386/compile/core i386

>Description:
	dd(1) uses not safe interrupt handlers, they may leads to strange problems
with dd

>How-To-Repeat:

	man 2 sigaction

>Fix:

diff -u /usr/src/bin/dd/dd.c dd/dd.c
--- /usr/src/bin/dd/dd.c	Fri Oct  1 18:30:06 2004
+++ dd/dd.c	Sun Dec 19 11:31:44 2004
@@ -89,7 +89,7 @@
 	jcl(argv);
 	setup();
 
-	(void)signal(SIGINFO, summaryx);
+	(void)signal(SIGINFO, siginfo_handler);
 	(void)signal(SIGINT, terminate);
 
 	atexit(summary);
@@ -311,6 +311,7 @@
 			if (!(ddflags & C_NOERROR))
 				err(1, "%s", in.name);
 			warn("%s", in.name);
+			need_summary = 0;
 			summary();
 
 			/*
@@ -368,6 +369,10 @@
 
 		in.dbp += in.dbrcnt;
 		(*cfunc)();
+		if (need_summary) {
+			need_summary = 0;
+			summary();
+		}
 	}
 }
 
diff -u /usr/src/bin/dd/extern.h dd/extern.h
--- /usr/src/bin/dd/extern.h	Fri Oct  1 18:30:06 2004
+++ dd/extern.h	Sun Dec 19 11:32:53 2004
@@ -43,7 +43,7 @@
 void pos_in(void);
 void pos_out(void);
 void summary(void);
-void summaryx(int);
+void siginfo_handler(int);
 void terminate(int);
 void unblock(void);
 void unblock_close(void);
@@ -61,3 +61,5 @@
 extern const u_char a2ibm_32V[], a2ibm_POSIX[];
 extern u_char casetab[];
 extern char fill_char;
+
+int need_summary;
diff -u /usr/src/bin/dd/misc.c dd/misc.c
--- /usr/src/bin/dd/misc.c	Fri Oct  1 18:30:06 2004
+++ dd/misc.c	Sun Dec 19 11:32:01 2004
@@ -85,13 +85,9 @@
 }
 
 /* ARGSUSED */
-void
-summaryx(int notused __unused)
+void siginfo_handler(int signo __unused)
 {
-	int save_errno = errno;
-
-	summary();
-	errno = save_errno;
+	need_summary = 1;
 }
 
 /* ARGSUSED */
@@ -102,3 +98,4 @@
 	summary();
 	_exit(sig == 0 ? 0 : 1);
 }
+
diff -u /usr/src/bin/dd/position.c dd/position.c
--- /usr/src/bin/dd/position.c	Fri Oct  1 18:30:06 2004
+++ dd/position.c	Sun Dec 19 11:33:19 2004
@@ -91,6 +91,10 @@
 				}
 			} else
 				--cnt;
+			if (need_summary) {
+				need_summary = 0;
+				summary();
+			}
 			continue;
 		}
 
@@ -111,6 +115,7 @@
 			if (!warned) {
 				warn("%s", in.name);
 				warned = 1;
+				need_summary = 0;
 				summary();
 			}
 			continue;


>Release-Note:
>Audit-Trail:

From: Maxim Konovalov <maxim@macomnet.ru>
To: "Oleg V. Nauman" <oleg@reis.zp.ua>
Cc: bug-followup@freebsd.org
Subject: Re: bin/75258: [patch] dd(1) has not async signal safe interrupt
 handlers
Date: Sun, 19 Dec 2004 18:11:06 +0300 (MSK)

 [...]
 > >Description:
 > 	dd(1) uses not safe interrupt handlers, they may leads to
 > strange problems with dd
 
 Are you sure?  Do you have a testcase?
 
 > >How-To-Repeat:
 >
 > 	man 2 sigaction
 
 Well, stdio(3) is not signal-safe in general but it seems for me
 summary() does not manipulate with the internal state of any file
 descriptors (it uses write(2)) and should be safe.
 
 Browseing the commit history says the same.
 
 [...]
 > +int need_summary;
 
 This should be volatile sig_atomic_t.
 
 -- 
 Maxim Konovalov

From: "Oleg V. Nauman" <oleg@reis.zp.ua>
To: Maxim Konovalov <maxim@macomnet.ru>
Cc: bug-followup@freebsd.org
Subject: Re: bin/75258: [patch] dd(1) has not async signal safe interrupt handlers
Date: Sun, 19 Dec 2004 17:29:59 +0200

 --VrqPEDrXMn8OVzN4
 Content-Type: text/plain; charset=koi8-r
 Content-Disposition: inline
 Content-Transfer-Encoding: quoted-printable
 
 On Sun, Dec 19, 2004 at 06:11:06PM +0300, Maxim Konovalov wrote:
 > [...]
 > > >Description:
 > > 	dd(1) uses not safe interrupt handlers, they may leads to
 > > strange problems with dd
 >=20
 > Are you sure?  Do you have a testcase?
 
 	No, sorry.
 
 >=20
 > > >How-To-Repeat:
 > >
 > > 	man 2 sigaction
 >=20
 > Well, stdio(3) is not signal-safe in general but it seems for me
 > summary() does not manipulate with the internal state of any file
 > descriptors (it uses write(2)) and should be safe.
 
 	But s*printf() family uses malloc(3) for his internal purposes,
 and there is no any reasons for things like memory allocations in
 the signal handler, I think.
 
 >=20
 > Browseing the commit history says the same.
 >=20
 > [...]
 > > +int need_summary;
 >=20
 > This should be volatile sig_atomic_to.
 
 	Yes, you are right, thank you.
 
 >=20
 > --=20
 > Maxim Konovalov
 
 --=20
 NO37-RIPE
 
 --VrqPEDrXMn8OVzN4
 Content-Type: application/pgp-signature
 Content-Disposition: inline
 
 -----BEGIN PGP SIGNATURE-----
 Version: PGP 6.5.8
 
 iQCVAwUBQcWeZ/C2y8Tb/5DvAQFWZgP/YY9BfKFkTS1Tjp/9B5iEz85TJAHjslV1
 UvK0TlY0LX/R7DWf3d9JUY9KB6NRscuIpoGz5aIH9X4SAZXwzAdUrGHupmOmF8DZ
 VxlBbPjM2f/saexVzKOw6MURaxZC3JAW5K4jLACSIPEQeSUTMcQJQqopnYQ7bBHK
 iWc2Iy/FtfY=
 =WXGA
 -----END PGP SIGNATURE-----
 
 --VrqPEDrXMn8OVzN4--

From: Bruce Evans <bde@zeta.org.au>
To: "Oleg V. Nauman" <oleg@reis.zp.ua>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: bin/75258: [patch] dd(1) has not async signal safe interrupt
 handlers
Date: Wed, 29 Dec 2004 01:14:39 +1100 (EST)

 [gnats put back in Cc and everything quoted so that gnats sees it]
 
 On Tue, 28 Dec 2004, Oleg V. Nauman wrote:
 
 > On Fri, Dec 24, 2004 at 02:22:19AM +1100, Bruce Evans wrote:
 > > On Sun, 19 Dec 2004, Oleg V. Nauman wrote:
 > >
 > > >  On Sun, Dec 19, 2004 at 06:11:06PM +0300, Maxim Konovalov wrote:
 > > >  > [...]
 > > >  > > >Description:
 > > >  > > 	dd(1) uses not safe interrupt handlers, they may leads to
 > > >  > > strange problems with dd
 > > >  >=20
 > > >  > Are you sure?  Do you have a testcase?
 > > >
 > > >  	No, sorry.
 > >
 > > However, the patch in the PR would cause strange problems like breaking
 > > termination of dd when the input is from certain slow devices, e.g.,
 > > terminals.  Input is normally restarted after a signal, so just setting
 > > a flag in the signal handler normally doesn't work.  Most "fixes" for
 > > unsafe signal handling get this wrong.  To get this right, something
 > > like the following must be done:
 > > - use sigaction() without SA_RESTART instead of signal(), or use
 > >   siginterrupt() to turn off SA_RESTART.  I've only seen this done
 > >   right for fixing unsafe signal handling in ping(8)  I've seen it
 > >   done wrong in top(1) (try hitting ^C in command mode in top).
 > > - handle the resulting EINTR errors from all syscalls that may now
 > >   fail with this error instead of being restarted.  This is difficult
 > >   or impossible in large programs.  If the signal is checked for and
 > >   acted on after every EINTR, then you have the same problem as acting
 > >   on it directly in signal handlers (the syscall might be in a context
 > >   that doesn't or shouldn't know if it is safe to act), plus
 > >   maintainence problems for checking and acting all over.  If the
 > >   acton is delayed, then the program must somehow be structured to
 > >   ensure that control is passed up to a level that can safely act;
 > >   in particular, no more syscalls that might block can be made.  I
 > >   suppose the latter could be implemented simply but laboriously by
 > >   wrapping all syscalls with
 > >   { if (signalflag) { errno = EINTR; return (-1); } else { normalcall(); }.
 >
 > 	Thank you for your feedback. It looks like I'm could write much more
 > better patch :)
 >
 > >
 > > >  >=20
 > > >  > > >How-To-Repeat:
 > > >  > >
 > > >  > > 	man 2 sigaction
 > > >  >=20
 > > >  > Well, stdio(3) is not signal-safe in general but it seems for me
 > > >  > summary() does not manipulate with the internal state of any file
 > > >  > descriptors (it uses write(2)) and should be safe.
 > > >
 > > >  	But s*printf() family uses malloc(3) for his internal purposes,
 > > >  and there is no any reasons for things like memory allocations in
 > > >  the signal handler, I think.
 > >
 > > s*printf() needs to be signal-safe in practice.  It is careful to use
 > > only local storage for this reason.  Only asprintf() uses malloc().
 >
 > 	It looks like snprintf() calls __vfprintf(), which calls __wcsconv()
 > and __find_arguments() (/usr/src/lib/libc/stdio/vfprintf.c on my
 > RELENG_5 system)
 > These functions directly calls malloc() (without counts how many
 > calls indirectly)
 
 Urk.  vfprintf.c also calls reallocf() directly, and some generic locale
 functions which may call malloc(), and for floating point it calls the
 gdtoa library which uses its own allocator that has much the same issues
 as malloc() (both have locking, but it doesn't help since it is null in
 the non-threaded case and would deadlock if reentered in the threaded
 case).  And dd/misc.c:summary() uses a floating point format.
 
 >
 > >
 > > summary() is obviously attempting to be signal-safe (even in rev.1.1).
 > > It avoids using printf() but depends on snprintf() being signal safe
 > > since the formatting would be too hard otherwise.
 > >
 > > Bruce
 
 I suppose making s*printf() signal-safe again is too hard, but Cc'ed some
 library maintainers to see what they think.  vfprintf.c is apparently
 intended to be signal-safe in 4.4BSD, but things are more complicated
 now.  In 4.4BSD, it has only the following external references:
          U __divdi3
          U __dtoa
          U __fpclassifyd
          U __moddi3
          U __sfvwrite
          U __swsetup
          U __udivdi3
          U __umoddi3
          U abort
          U fflush
          U memchr
 00000308 T vfprintf
 
 Here:
 - __fpclassifyd() is from a macro in current headers and isn't in 4.4BSD.
   It and the other general low-level functions are probably signal-safe.
 - dtoa() is even less signal-safe in 4.4BSD than in -current, since it
   calls malloc() in 4.4BSD.
 - the low-level stdio functions are probably signal-safe for s*printf().
   The main case where they aren't signal-safe is when __swsetup() and/or
   friends call malloc() for file i/o.
 - the standard function abort() is required to be signal-safe in a weak
   sense in C99, but POSIX requires it to flush stdio buffers so it cannot
   reasonably be signal-safe.  FreeBSD implements the POSIX requirement.
   This isn't a problem in 4.4BSD since abort() is only called in cases
   that can't happen.  -current also calls it for malloc() failures.
 - the standard function fflush() is not required to be signal-safe but
   probably is for s*printf() in FreeBSD.
 - the standard function memchr() is not required to be signal-safe but
   probably is in FreeBSD.
 
 The June version of vfprintf.o has the the following external references:
 
          U __divdi3
          U __dtoa
          U __fflush
          U __freedtoa
          U __hdtoa
          U __hldtoa
          U __isthreaded
          U __ldtoa
          U __moddi3
          U __sfvwrite
          U __swsetup
          U __udivdi3
          U __umoddi3
          U _flockfile
          U _funlockfile
          U abort
          U bcopy
          U free
          U localeconv
          U malloc
          U memchr
          U reallocf
          U wcrtomb
          U wcsrtombs
 00000570 T vfprintf
 000005c8 T __vfprintf
 
 The call to localconv() seems to be especially dangerous since it can
 result in updating global locale data.
 
 Bruce
State-Changed-From-To: open->closed 
State-Changed-By: eadler 
State-Changed-When: Fri May 10 18:44:36 UTC 2013 
State-Changed-Why:  
Committed. Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=75258 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/75258: commit references a PR
Date: Fri, 10 May 2013 18:43:45 +0000 (UTC)

 Author: eadler
 Date: Fri May 10 18:43:36 2013
 New Revision: 250469
 URL: http://svnweb.freebsd.org/changeset/base/250469
 
 Log:
   Make dd's signal handler async safe.
   
   PR:		bin/75258
   Submitted by:	"Oleg V. Nauman" <oleg@reis.zp.ua>
   Arrival Date:	Sun Dec 19 14:50:21 GMT 2004
   Reviewed by:	mjg, jhb
   Reviewed by:	jilles (earlier version)
   MFC after:	1 week
 
 Modified:
   head/bin/dd/args.c
   head/bin/dd/conv_tab.c
   head/bin/dd/dd.c
   head/bin/dd/extern.h
   head/bin/dd/misc.c
   head/bin/dd/position.c
 
 Modified: head/bin/dd/args.c
 ==============================================================================
 --- head/bin/dd/args.c	Fri May 10 18:41:14 2013	(r250468)
 +++ head/bin/dd/args.c	Fri May 10 18:43:36 2013	(r250469)
 @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
  #include <errno.h>
  #include <inttypes.h>
  #include <limits.h>
 +#include <signal.h>
  #include <stdlib.h>
  #include <string.h>
  
 
 Modified: head/bin/dd/conv_tab.c
 ==============================================================================
 --- head/bin/dd/conv_tab.c	Fri May 10 18:41:14 2013	(r250468)
 +++ head/bin/dd/conv_tab.c	Fri May 10 18:43:36 2013	(r250469)
 @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
  
  #include <sys/types.h>
  
 +#include <signal.h>
  #include <stdint.h>
  
  #include "dd.h"
 
 Modified: head/bin/dd/dd.c
 ==============================================================================
 --- head/bin/dd/dd.c	Fri May 10 18:41:14 2013	(r250468)
 +++ head/bin/dd/dd.c	Fri May 10 18:43:36 2013	(r250469)
 @@ -81,6 +81,7 @@ size_t	cbsz;			/* conversion block size 
  uintmax_t files_cnt = 1;	/* # of files to copy */
  const	u_char *ctab;		/* conversion table */
  char	fill_char;		/* Character to fill with if defined */
 +volatile sig_atomic_t need_summary;
  
  int
  main(int argc __unused, char *argv[])
 @@ -89,7 +90,7 @@ main(int argc __unused, char *argv[])
  	jcl(argv);
  	setup();
  
 -	(void)signal(SIGINFO, summaryx);
 +	(void)signal(SIGINFO, siginfo_handler);
  	(void)signal(SIGINT, terminate);
  
  	atexit(summary);
 @@ -375,6 +376,9 @@ dd_in(void)
  
  		in.dbp += in.dbrcnt;
  		(*cfunc)();
 +		if (need_summary) {
 +			summary();
 +		}
  	}
  }
  
 
 Modified: head/bin/dd/extern.h
 ==============================================================================
 --- head/bin/dd/extern.h	Fri May 10 18:41:14 2013	(r250468)
 +++ head/bin/dd/extern.h	Fri May 10 18:43:36 2013	(r250469)
 @@ -43,7 +43,7 @@ void jcl(char **);
  void pos_in(void);
  void pos_out(void);
  void summary(void);
 -void summaryx(int);
 +void siginfo_handler(int);
  void terminate(int);
  void unblock(void);
  void unblock_close(void);
 @@ -61,3 +61,4 @@ extern const u_char e2a_32V[], e2a_POSIX
  extern const u_char a2ibm_32V[], a2ibm_POSIX[];
  extern u_char casetab[];
  extern char fill_char;
 +extern volatile sig_atomic_t need_summary;
 
 Modified: head/bin/dd/misc.c
 ==============================================================================
 --- head/bin/dd/misc.c	Fri May 10 18:41:14 2013	(r250468)
 +++ head/bin/dd/misc.c	Fri May 10 18:43:36 2013	(r250469)
 @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
  
  #include <errno.h>
  #include <inttypes.h>
 +#include <signal.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
 @@ -57,41 +58,32 @@ summary(void)
  {
  	struct timeval tv;
  	double secs;
 -	char buf[100];
  
  	(void)gettimeofday(&tv, NULL);
  	secs = tv.tv_sec + tv.tv_usec * 1e-6 - st.start;
  	if (secs < 1e-6)
  		secs = 1e-6;
 -	/* Use snprintf(3) so that we don't reenter stdio(3). */
 -	(void)snprintf(buf, sizeof(buf),
 +	(void)fprintf(stderr,
  	    "%ju+%ju records in\n%ju+%ju records out\n",
  	    st.in_full, st.in_part, st.out_full, st.out_part);
 -	(void)write(STDERR_FILENO, buf, strlen(buf));
 -	if (st.swab) {
 -		(void)snprintf(buf, sizeof(buf), "%ju odd length swab %s\n",
 +	if (st.swab)
 +		(void)fprintf(stderr, "%ju odd length swab %s\n",
  		     st.swab, (st.swab == 1) ? "block" : "blocks");
 -		(void)write(STDERR_FILENO, buf, strlen(buf));
 -	}
 -	if (st.trunc) {
 -		(void)snprintf(buf, sizeof(buf), "%ju truncated %s\n",
 +	if (st.trunc)
 +		(void)fprintf(stderr, "%ju truncated %s\n",
  		     st.trunc, (st.trunc == 1) ? "block" : "blocks");
 -		(void)write(STDERR_FILENO, buf, strlen(buf));
 -	}
 -	(void)snprintf(buf, sizeof(buf),
 +	(void)fprintf(stderr,
  	    "%ju bytes transferred in %.6f secs (%.0f bytes/sec)\n",
  	    st.bytes, secs, st.bytes / secs);
 -	(void)write(STDERR_FILENO, buf, strlen(buf));
 +	need_summary = 0;
  }
  
  /* ARGSUSED */
  void
 -summaryx(int notused __unused)
 +siginfo_handler(int signo __unused)
  {
 -	int save_errno = errno;
  
 -	summary();
 -	errno = save_errno;
 +	need_summary = 1;
  }
  
  /* ARGSUSED */
 
 Modified: head/bin/dd/position.c
 ==============================================================================
 --- head/bin/dd/position.c	Fri May 10 18:41:14 2013	(r250468)
 +++ head/bin/dd/position.c	Fri May 10 18:43:36 2013	(r250469)
 @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
  #include <err.h>
  #include <errno.h>
  #include <inttypes.h>
 +#include <signal.h>
  #include <unistd.h>
  
  #include "dd.h"
 @@ -91,6 +92,8 @@ pos_in(void)
  				}
  			} else
  				--cnt;
 +			if (need_summary)
 +				summary();
  			continue;
  		}
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
