/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation, either version 3 or (at your option) any *
* later version. This program is distributed without any warranty. See *
* the file COPYING.gpl-v3 for details. *
\*************************************************************************//* Listing 21-1 *//* nonreentrant.cDemonstrate the nonreentrant nature of some library functions, in thisexample, crypt(3).
*/#if ! defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600#define _XOPEN_SOURCE 600#endif#include<unistd.h>#include<signal.h>#include<string.h>#include"tlpi_hdr.h"staticchar*str2;/* Set from argv[2] */staticint handled =0;/* Counts number of calls to handler */staticvoidhandler(int sig){crypt(str2,"xx");handled++;}intmain(int argc,char*argv[]){char*cr1;int callNum, mismatch;struct sigaction sa;if(argc !=3)usageErr("%s str1 str2\n", argv[0]);str2 = argv[2];/* Make argv[2] available to handler */cr1 =strdup(crypt(argv[1],"xx"));/* Copy statically allocated stringto another buffer */if(cr1 ==NULL)errExit("strdup");sigemptyset(&sa.sa_mask);sa.sa_flags =0;sa.sa_handler = handler;if(sigaction(SIGINT,&sa,NULL)==-1)errExit("sigaction");/* Repeatedly call crypt() using argv[1]. If interrupted by asignal handler, then the static storage returned by crypt()will be overwritten by the results of encrypting argv[2], andstrcmp() will detect a mismatch with the value in 'cr1'. *//*** @brief 正常情況下,處理同一個(gè)字符得出的結(jié)果肯定是相同的,但是當(dāng)捕捉到Crt+C之后就會(huì)出現(xiàn)不一樣的結(jié)果,因?yàn)樾盘?hào)處理函數(shù)中斷了加密函數(shù)的執(zhí)行* @note 因此一旦捕捉到信號(hào)就會(huì),進(jìn)入到if判斷條件,出現(xiàn)打印的結(jié)果* @param 1: * @param callNum++: * @retval */for(callNum =1, mismatch =0;; callNum++){if(strcmp(crypt(argv[1],"xx"), cr1)!=0){mismatch++;printf("Mismatch on call %d (mismatch=%d handled=%d)\n",callNum, mismatch, handled);}}}
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation, either version 3 or (at your option) any *
* later version. This program is distributed without any warranty. See *
* the file COPYING.gpl-v3 for details. *
\*************************************************************************//* Listing 21-2 *//* sigmask_longjmp.cDemonstrate the different effects of longjmp() and siglongjmp()on the process signal mask.By default, this program uses setjmp() + longjmp(). Compile with-DUSE_SIGSETJMP to use sigsetjmp() + siglongjmp().
*/#define _GNU_SOURCE /* Get strsignal() declaration from <string.h> */#include<string.h>#include<setjmp.h>#include<signal.h>#include"signal_functions.h"/* Declaration of printSigMask() */#include"tlpi_hdr.h"staticvolatile sig_atomic_t canJump =0;/* Set to 1 once "env" buffer has beeninitialized by [sig]setjmp() */#ifdef USE_SIGSETJMPstatic sigjmp_buf senv;#elsestatic jmp_buf env;#endifstaticvoidhandler(int sig){/* UNSAFE: This handler uses non-async-signal-safe functions(printf(), strsignal(), printSigMask(); see Section 21.1.2) */printf("Received signal %d (%s), signal mask is:\n", sig,strsignal(sig));printSigMask(stdout,NULL);if(!canJump){printf("'env' buffer not yet set, doing a simple return\n");return;}#ifdef USE_SIGSETJMPsiglongjmp(senv,1);#elselongjmp(env,1);#endif}intmain(int argc,char*argv[]){struct sigaction sa;printSigMask(stdout,"Signal mask at startup:\n");sigemptyset(&sa.sa_mask);sa.sa_flags =0;sa.sa_handler = handler;if(sigaction(SIGINT,&sa,NULL)==-1)errExit("sigaction");#ifdef USE_SIGSETJMPprintf("Calling sigsetjmp()\n");if(sigsetjmp(senv,1)==0)#elseprintf("Calling setjmp()\n");if(setjmp(env)==0)#endifcanJump =1;/* Executed after [sig]setjmp() */else/* Executed after [sig]longjmp() */printSigMask(stdout,"After jump from handler, signal mask is:\n");for(;;)/* Wait for signals until killed */pause();}
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation, either version 3 or (at your option) any *
* later version. This program is distributed without any warranty. See *
* the file COPYING.gpl-v3 for details. *
\*************************************************************************//* Listing 21-3 *//* t_sigaltstack.cDemonstrate the use of sigaltstack() to handle a signal on an alternatesignal stack.
*/#define _GNU_SOURCE /* Get strsignal() declaration from <string.h> */#include<string.h>#include<signal.h>#include"tlpi_hdr.h"staticvoidsigsegvHandler(int sig){int x;/* UNSAFE: This handler uses non-async-signal-safe functions(printf(), strsignal(), fflush(); see Section 21.1.2) */printf("Caught signal %d (%s)\n", sig,strsignal(sig));printf("Top of handler stack near %10p\n",(void*)&x);fflush(NULL);_exit(EXIT_FAILURE);/* Can't return after SIGSEGV */}/* The following stops 'gcc -Wall' complaining that "control reachesend of non-void function" because we don't follow the call tooverflowStack() stack in main() with a call to exit(). */#ifdef __GNUC__staticvoidoverflowStack(int callNum) __attribute__ ((__noreturn__));#endifstaticvoid/* A recursive function that overflows the stack */overflowStack(int callNum)//連續(xù)調(diào)用知道程序的棧溢出{char a[100000];/* Make this stack frame large */printf("Call %4d - top of stack near %10p\n", callNum,&a[0]);overflowStack(callNum+1);}intmain(int argc,char*argv[]){stack_t sigstack;struct sigaction sa;int j;printf("Top of standard stack is near %10p\n",(void*)&j);/* Allocate alternate stack and inform kernel of its existence */sigstack.ss_sp =malloc(SIGSTKSZ);if(sigstack.ss_sp ==NULL)errExit("malloc");sigstack.ss_size = SIGSTKSZ;sigstack.ss_flags =0;if(sigaltstack(&sigstack,NULL)==-1)errExit("sigaltstack");printf("Alternate stack is at %10p-%p\n",sigstack.ss_sp,(char*)sbrk(0)-1);sa.sa_handler = sigsegvHandler;/* Establish handler for SIGSEGV */sigemptyset(&sa.sa_mask);sa.sa_flags = SA_ONSTACK;/* Handler uses alternate stack */if(sigaction(SIGSEGV,&sa,NULL)==-1)errExit("sigaction");overflowStack(1);}
可見上述函數(shù)就算棧溢出,信號(hào)處理器也能夠正常的執(zhí)行
$ ./t_sigaltstack
Top of standard stack is near 0x7ffd2c51877c
Alternate stack is at 0x1f83420-0x1fa3fff
Call 1 - top of stack near 0x7ffd2c5000a0
Call 2 - top of stack near 0x7ffd2c4e79d0
Call 3 - top of stack near 0x7ffd2c4cf300
Call 4 - top of stack near 0x7ffd2c4b6c30
Call 5 - top of stack near 0x7ffd2c49e560
...
Call 77 - top of stack near 0x7ffd2bdbfae0
Call 78 - top of stack near 0x7ffd2bda7410
Call 79 - top of stack near 0x7ffd2bd8ed40
Call 80 - top of stack near 0x7ffd2bd76670
Call 81 - top of stack near 0x7ffd2bd5dfa0
Call 82 - top of stack near 0x7ffd2bd458d0
Call 83 - top of stack near 0x7ffd2bd2d200
Caught signal 11 (Segmentation fault)
Top of handler stack near 0x1f84ee4
andrew@andrew-Thurley:/work/svn_linux/linux_unix/sys