257 lines
13 KiB
HTML
257 lines
13 KiB
HTML
<!--startcut ==============================================-->
|
|
<!-- *** BEGIN HTML header *** -->
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
<HTML><HEAD>
|
|
<title>setjmp/longjmp Illustrated LG #90</title>
|
|
</HEAD>
|
|
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
|
|
ALINK="#FF0000">
|
|
<!-- *** END HTML header *** -->
|
|
|
|
<!-- *** BEGIN navbar *** -->
|
|
<A HREF="puryear.html"><< Prev</A> | <A HREF="index.html">TOC</A> | <A HREF="../index.html">Front Page</A> | <A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue90/raghu.html">Talkback</A> | <A HREF="../faq/index.html">FAQ</A> | <A HREF="ward.html">Next >></A>
|
|
<!-- *** END navbar *** -->
|
|
|
|
<!--endcut ============================================================-->
|
|
|
|
<TABLE BORDER><TR><TD WIDTH="200">
|
|
<A HREF="http://www.linuxgazette.com/">
|
|
<IMG ALT="LINUX GAZETTE" SRC="../gx/2002/lglogo_200x41.png"
|
|
WIDTH="200" HEIGHT="41" border="0"></A>
|
|
<BR CLEAR="all">
|
|
<SMALL>...<I>making Linux just a little more fun!</I></SMALL>
|
|
</TD><TD WIDTH="380">
|
|
|
|
|
|
<CENTER>
|
|
<BIG><BIG><STRONG><FONT COLOR="maroon">setjmp/longjmp Illustrated</FONT></STRONG></BIG></BIG>
|
|
<BR>
|
|
<STRONG>By <A HREF="../authors/raghu.html">Raghu J Menon</A></STRONG>
|
|
</CENTER>
|
|
|
|
</TD></TR>
|
|
</TABLE>
|
|
<P>
|
|
|
|
<!-- END header -->
|
|
|
|
|
|
|
|
<p>The setjmp/longjmp set of macros implemented in the C
|
|
programming language provide the perfect platform to perform complex
|
|
flow-control, but make sure that you have gained adequate knowledge about them,
|
|
before you actually use them, or else your programs could become so complex
|
|
that it would be impossible to discern them. </p>
|
|
<p>What do they do?</p>
|
|
<p>The setjmp function saves the state of a program. The state of
|
|
a program to be precise are the values of sp (stack pointer), fp (frame
|
|
pointer), pc (program counter). A program state is completely defined by these
|
|
set of registers and the contents of the memory, which includes the heap and the
|
|
stack. The next obvious question would be, why do i need to save the state for?
|
|
Well simple to restore it later through longjmp. So these functions hunt
|
|
in pairs i.e. setjmp saves the state, longjmp restores it.</p>
|
|
<H2>The syntax....</H2>
|
|
<p>The syntax is quite simple. setjmp stores the state of the
|
|
program in a variable of type jmp_buf (defined in the header file setjmp.h).
|
|
Always include the header file while working with these functions.</p>
|
|
<CODE>
|
|
<p>int setjmp (jmp_buf env);</p>
|
|
<p>int longjmp(jmp_buf env , int val);</p>
|
|
</CODE>
|
|
<p>The longjmp function restores the state of the program that is
|
|
stored in env. The purpose of the parameter val will be explained later. So what
|
|
does all this add upto? Simply that the longjmp function never returns (another
|
|
one after exec). Before encountering a longjmp there has to be a setjmp which
|
|
saves the state in env and returns a value 0. When you encounter longjmp next
|
|
the state stored in env is restored and the program execution resumes at the
|
|
instruction after setjmp. It is as though the longjmp returned through setjmp.
|
|
This return should yield a value though and that value is what is specified
|
|
through the parameter val.</p>
|
|
<CODE>
|
|
<p>i = setjmp (env);//Stores the state in env and returns 0</p>
|
|
<p>........... //Resume execution
|
|
at this point after the longjmp call as though the setjmp call</p>
|
|
<p>....... //returned. </p>
|
|
<p></p>
|
|
<p></p>
|
|
<p> </p>
|
|
<p>longjmp(env,val)</p>
|
|
</CODE>
|
|
<p>As a last point, try printing the value of i. You would get 2
|
|
values, the first one is that obtained when setjmp saves the state and will be 0
|
|
always. The second one will be the value that you pass to longjmp through the
|
|
val parameter. So the code after setjmp seems to get executed more than once.
|
|
That calls for some exploration. We therefore have our first code and an
|
|
interesting one too. <a href="misc/raghu/if-else.c.txt">if-else.c</a></p>
|
|
<p> Compile and run it. I hope you noticed it, both the if
|
|
and else part of the condition are executed! Now, that is not how if-else
|
|
condition is supposed to work. Looks like fork() (parent executing the if part
|
|
and child executing the else or vice-versa). Well in fork we have two different
|
|
threads of execution, that is not the case here. The setjmp call saves the state
|
|
in env and returns 0. The if condition evaluates to true and you get the first
|
|
message. Now later in the code when longjmp is executed the state is restored
|
|
and you return to the statement following setjmp with a return value 2. </p>
|
|
<p>This
|
|
return value is specified in the longjmp call. Now you see why the if condition
|
|
failed and the else was executed. In addition the program showed disparity by
|
|
not executing the last line. Well as i said earlier longjmp never returns and so
|
|
it is quite obvious why the last line is not executed. If you take out the exit
|
|
statement the code falls into a never ending loop alternating between the else
|
|
part and the longjmp call.</p>
|
|
<H2>Some thing more useful please.....</H2>
|
|
<p>As programmers you might have written code by dividing it
|
|
into functions or subroutines (If not learn the art of functional programming. I
|
|
started off by writing a C program as one big main function, gradually though i
|
|
was able to split my program into functions. Why? It is easier to debug,
|
|
that's why.). In implementing your program as functions there are bound to be
|
|
function calls that are nested, that have pretty complex flow as well. Whenever an
|
|
error occurs you need to find the function that caused it. This way it is easier
|
|
to debug the program. The code below illustrates the use of setjmp/longjmp pair
|
|
in debugging such programs. <a href="misc/raghu/nest.c.txt">nest.c</a></p>
|
|
<p>Well the program does not do anything useful other than serve
|
|
the purpose of illustrating graceful error handling. The code defines 4
|
|
functions, each one of them apart from accepting specified number of integer
|
|
parameters, also has env as its parameter. The env holds the state of the
|
|
program saved by the setjmp call in the main function. The failure in executing
|
|
each of the function is specified in the if condition. Compile the program and
|
|
execute it. Enter the following sets of values for l, m, n.</p>
|
|
<CODE>
|
|
<p>Enter values (integer) for l m and n please</p>
|
|
<p>1 </p>
|
|
<p>4</p>
|
|
<p>7</p>
|
|
<p>The functions executed normally</p>
|
|
<p><br>
|
|
Enter values (integer) for l m and n please</p>
|
|
<p>0</p>
|
|
<p>0</p>
|
|
<p>0</p>
|
|
<p>There is an error in function 1 exiting..<br>
|
|
</p>
|
|
<p>Enter values (integer) for l m and n please</p>
|
|
<p>1</p>
|
|
<p>1</p>
|
|
<p>2</p>
|
|
<p>There is an error in function 2 exiting..<br>
|
|
</p>
|
|
<p>Enter values (integer) for l m and n please</p>
|
|
<p>0</p>
|
|
<p>1</p>
|
|
<p>2</p>
|
|
<p>There is an error in function 3 exiting..</p>
|
|
<p><br>
|
|
Enter values (integer) for l m and n please</p>
|
|
<p>1</p>
|
|
<p>2</p>
|
|
<p>3</p>
|
|
<p>There is an error in function 4 exiting..<br>
|
|
</p>
|
|
</CODE>
|
|
<p> Well that was useful i suppose. The error message could
|
|
tell you where the error occurred. Let us trace the code. The setjmp in the main
|
|
function saves the state of the program and returns 0. The if condition equates
|
|
to false and therefore is not executed. The next statement calls the function
|
|
fun1 with parameters env, l, m, n, fun1 in turn calls fun2 and so on. Whenever
|
|
an error occurs in any of these functions a longjmp is executed, the val
|
|
parameter being the function number where the longjmp was executed. The program
|
|
returns to the main function (to the statement after setjmp) whenever a longjmp
|
|
is executed. The value in s now is either 1, 2, 3, 4, depending on where the
|
|
longjmp was made from. The if condition now equates to truth value and therefore
|
|
an appropriate error message is flagged indicating the function in which the
|
|
error occurred. If no error occurred during the execution of the program the
|
|
functions return normally and the last statement of the main function is
|
|
executed. Why don't i just
|
|
use the goto statement to make a jump during an error? Try compiling the code below <a href="misc/raghu/goto.c.txt">goto.c</a>. The error flagged is
|
|
because goto can be used only for local jumps. The jumps in the previous program
|
|
made by longjmp where non-local ones, goto searches for local labels and hence
|
|
cannot make non-local jumps.</p>
|
|
<p> </p>
|
|
<H2>Vulnerability Of The Programmer........</H2>
|
|
<p>There is a subtle bug in setjmp/longjmp, not in its
|
|
implementation, but in the way we use it. Most of us are quite unaware and
|
|
rightly so of the stack state when we write a program. It is when there is an
|
|
error we try and trace it by inspecting the stack (through gdb). Whenever there
|
|
is a function call the stack is manipulated. First the arguments to the called
|
|
function are pushed in the reverse order. Next the JSR is called to push the
|
|
return address (pc) and then the fp, fp and sp are then emptied to make a new
|
|
stack frame for the called function. The called function immediately on entry
|
|
creates space on the stack for the local variables that might have been declared
|
|
in the function. Now that you have an idea of the stack structure, try running
|
|
the code below <a href="misc/raghu/seg.c.txt">seg.c</a>. It compiles fine, but alas it fails to run completely
|
|
and faults. Could you find the reason? </p>
|
|
<p> Let us trace the
|
|
code. The main function calls me_first with 2 arguments, the
|
|
arguments are pushed onto the stack env followed by the string "IC-Labs", the
|
|
JSR then pushes the pc and fp values on the stack. On entry the function
|
|
creates a local variable i on the stack. This is followed by a call to the setjmp
|
|
function which saves the current state, that of me_first function.
|
|
The local variable now contains the value 0, value returned by setjmp. After
|
|
returning from me_first the stack is returned to the original state, one
|
|
in which it left the main function. The i_follow function is called next with a
|
|
value 3 and the env variable. The stack is modified as above (when me_first was
|
|
called). In the function
|
|
the state stored in env is restored by longjmp. The values in the stack remain
|
|
the same i.e. as they where during the execution of function i_follow .
|
|
The state
|
|
though is that of function me_first. The stack frame of this state has a variable of type
|
|
(char * ) which previously had a string "IC-Labs". Now after the state has
|
|
been restored the value that variable s holds is 3 (the value that i_follow was passed
|
|
from the main). As a result of the longjmp the statement following setjmp in
|
|
me_first is executed. In executing the statement after setjmp (printf),
|
|
there is an illegal memory access since in trying to print out s the program
|
|
tries to find a string at memory location 0x3 which causes a memory protection
|
|
error and causes the program to fault. This bug is very subtle and often goes
|
|
unnoticed, this is because the stack frame of both the functions look almost the
|
|
same. In cases were the stack frames are the same there is no such error. Try
|
|
replacing the argument "char *" with one of type int, and rerun it. Did it fault?</p>
|
|
|
|
<H2>Signal Handling........</H2>
|
|
<p>One of the beauties of these functions is that you can longjmp
|
|
from a signal handler and return to your program and catch those signals again.
|
|
Check out the program below <a href="misc/raghu/sig.c.txt">sig.c</a></p>
|
|
<p>The main function installs a signal handler using the signal
|
|
system call, parameters are the signo(SIGALRM), which indicates the signal
|
|
for which you are setting up the handler and the handler routine which is
|
|
executed when the signal occurs. The alarm call sends the SIGALRM
|
|
signal to the program every second. The alarm_handler basically longjmps out
|
|
after 8 seconds have passed. </p>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- *** BEGIN author bio *** -->
|
|
<P>
|
|
<P>
|
|
<!-- *** BEGIN bio *** -->
|
|
<P>
|
|
<img ALIGN="LEFT" ALT="[BIO]" SRC="../gx/2002/note.png">
|
|
<em>
|
|
I am almost through with my graduate studies in computer
|
|
science and engineering. I hail from Trichur (a small town in god's own country,
|
|
Kerala). Any constructive criticism with regards to the style and content are
|
|
welcome. Please feel free to contact me via e-mail.
|
|
</em>
|
|
<br CLEAR="all">
|
|
<!-- *** END bio *** -->
|
|
|
|
<!-- *** END author bio *** -->
|
|
|
|
|
|
<!-- *** BEGIN copyright *** -->
|
|
<hr>
|
|
<CENTER><SMALL><STRONG>
|
|
Copyright © 2003, Raghu J Menon.
|
|
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
|
|
Published in Issue 90 of <i>Linux Gazette</i>, May 2003
|
|
</STRONG></SMALL></CENTER>
|
|
<!-- *** END copyright *** -->
|
|
<HR>
|
|
|
|
<!--startcut ==========================================================-->
|
|
<!-- *** BEGIN navbar *** -->
|
|
<A HREF="puryear.html"><< Prev</A> | <A HREF="index.html">TOC</A> | <A HREF="../index.html">Front Page</A> | <A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue90/raghu.html">Talkback</A> | <A HREF="../faq/index.html">FAQ</A> | <A HREF="ward.html">Next >></A>
|
|
<!-- *** END navbar *** -->
|
|
</BODY></HTML>
|
|
<!--endcut ============================================================-->
|