Home
Finding stale-value errors in concurrent programs
Contents
1. nezte 1 mod a length n n l exit_critical_section Analysis of the flow of this code will fail to prove that stale_a is false at the first assertion If this example were in a file ProduceConsume java then our checker would produce a warning like ProduceConsume java 82 Warning Possible use of stale value of monitored entity StaleValue v al nextc Aa where 82 is the source line number where the error was found and the caret indicates the position within the line 4 Experience We have applied our stale value checker to several concurrent Java programs We have found that the checker produces a modest number of warnings including some real 10 warnings program ao false alarms benign races bugs pachyclient mercator webl ambit cluster jigsaw sys man A sys man B Table The results of running our checker over various programs The table shows the program sizes and the number of warnings produced The warnings are broken up into three categories We are unsure of the categorization for ambit and jigsaw because we did not consult the authors of the code 0 1 0 0 0 0 0 0 0 0 1 0 0 3 0 0 errors in the programs The Table shows the results from running our checker The columns are the name of the program being tested the number of thousands of lines of code the number of false alarms generated by the tool the number of warnings that indicated benign races and the numbers of war
2. K Rustan M Leino Greg Nelson and James B Saxe Ex tended static checking Research Report 159 Compaq Systems Research Center December 1998 14 7 8 ey 9 p 10 11 12 13 Dawson Engler Benjamin Chelf Andy Chou and Seth Hallem Check ing system rules using system specific programmer written compiler exten sions In Proceedings of the Fourth Symposium on Operating Systems De sign amp Implementation USENIX October 2000 Proceedings published at http www usenix org events osdi2000 technical html Cormac Flanagan and Steven N Freund Type based race detection for Java In Proceedings of the 2000 ACM SIGPLAN conference on Programming Design and Implementation PLDI pages 219 232 2000 Cormac Flanagan K Rustan M Leino Mark Lillibridge Greg Nelson James B Saxe and Raymie Stata Extended static checking for Java In Proceedings of the 2002 ACM SIGPLAN Conference on Programming Language Design and Im plementation PLDI volume 37 number 5 in SIGPLAN Notices pages 234 245 ACM May 2002 C A R Hoare Monitors an operating system structuring concept Communica tions of the ACM 17 10 549 557 October 1974 K Rustan M Leino Greg Nelson and James B Saxe ESC Java user s manual Technical Note 2000 002 Compaq Systems Research Center October 2000 Stefan Savage Michael Burrows Greg Nelson Patrick Sobalvarro and Thomas E Anderson Eraser A dynamic data race detecto
3. checker adds the same ghost statements regardless of which lock is acquired This simple design may result in more stale value warnings than a more elaborate design However in trying out this simple initial design we found the number of reported warnings to be so low that it did not seem worth the time to design something more elaborate except at calls to synchronized methods as we describe next Another design consideration in our checker is that Java has a modifier called syn chronized that can be applied to methods Although this modifier looks like it is part of the signature of the method it is simply a convenient way to turn the body of a particular method implementation into a critical section Nevertheless by looking at this method modifier from call sites we have incorporated some special behavior in our checker A call to a synchronized method will enter and exit a critical section If the called method is declared in the same abstraction as the caller meaning in a superclass or subclass of the class enclosing the call and the call site is not itself in a critical section then our checker will treat the call as entering and exiting a critical section for the purpose of checking for stale value errors This has two implications The first implication regards entry to the call Our checker treats local variables mentioned in actual parameters of the call as though they were read by the callee To catch errors where the values of
4. one obtains the functionality of checking the condition stale_t correctly and retains the benefit of being able to do downstream checking We have described the various ghost statements above for local variables It would make sense also to treat formal parameters in this way since a formal parameter in Java method body can be used as a local variable In fact one can also imagine giving the same treatment to the temporary variables that ESC Java introduces to hold values of intermediate subexpressions However our implementation treats only local variables Finally we show how our checker would find a real error and the error message produced If our checker handled the pseudo code syntax of the third example from 9 Section 1 it would instrument it as follows ghost statments have comments enter_critical_section if from_critical_a then stale_a arbitrary end G2 if from_critical_v then stale_v arbitrary end G2 a ar stale_a false the assignment to a gives it a fresh value from_critical_a true GO while n 0 wait if from_critical_a then stale_a arbitrary end G2 the call to wait exits and re enters the critical section if from_critical_v then stale_v arbitrary end ditto assert stale_a about to read a v alneztc stale_v false the assignment to v gives it a fresh value from critical_v true GO assert stale_a about to read a nezte
5. Finding stale value errors in concurrent programs Michael Burrows K Rustan M Leino Compaq Systems Research Center Abstract Concurrent programs can suffer from many types of errors not just the well studied problems of deadlocks and simple race conditions on variables This pa per addresses a kind of race condition that arises from reading a variable whose value is possibly out of date The paper introduces a simple technique for detecting such stale values and reports on the encouraging experience with a compile time checker that uses the technique 0 Introduction Writing correctly behaving software programs is hard Among many kinds of errors errors due to concurrency are notoriously costly A reason that concurrency errors stand out is that it is difficult to devise test suites that will provoke the erroneous behaviors Therefore the prospect of using special program checkers for detecting concurrency errors has many appeals Of course there are costs involved in using a program checker too For example the checker may take a long time to run either affecting the running time of the pro gram itself or taking a long time to perform analyses at compile time Another possible cost associated with a program checker is that the warning messages it produces may be difficult to decipher or be too voluminous If much of the checker s output is seen by the user as unquenchable noise the checker is not likely to see much use Yet a
6. OOPSLA 2000 volume 35 number 10 in SIGPLAN Notices pages 382 400 ACM Octo ber 2000 Thomas Ball and Sriram K Rajamani Automatically validating temporal safety properties of interfaces In SPIN 2001 Workshop on Model Checking of Software volume 2057 of Lecture Notes in Computer Science pages 103 122 Springer Verlag May 2001 Andrew D Birrell An introduction to programming with threads Research Re port 35 Digital Equipment Corporation Systems Research Center January 1989 Chandrasekhar Boyapati and Martin Rinard A parameterized type system for race free Java programs In Proceedings of the 2001 ACM SIGPLAN Conference on Object Oriented Programming Systems Languages and Applications OOPSLA 2001 volume 36 number 11 in SIGPLAN Notices pages 56 69 ACM November 2001 Guang Ien Cheng Mingdong Feng Charles E Leiserson Keith H Randall and Andrew F Stark Detecting data races in Cilk programs that use locks In Pro ceedings of the Tenth Annual ACM Symposium on Parallel Algorithms and Archi tectures SPAA pages 298 309 June 1998 Jong Deok Choi Keunwoo Lee Alexey Loginov Robert O Callahan Vivek Sarkar and Manu Sridharan Efficient and precise datarace detection for multi threaded object oriented programs In Proceedings of the 2002 ACM SIGPLAN conference on Programming Language Design and Implementation PLDI vol ume 37 number 5 in SIGPLAN Notices pages 258 269 ACM May 2002 David L Detlefs
7. he critical section other threads obeying the monitored value paradigm will be excluded from accessing x However the sec ond access of x occurs outside the critical section and therefore mutual exclusion for accessing x is not ensured This means that another thread may be writing the vari able x at the time z is being read into t1 by the thread displayed above which would constitute a race condition Now consider a second more complicated example enter_critical_section t0 q exit_critical_section t1 t0 enter_critical_section t2 t0 exit_critical_section t3 10 where x is a shared variable and t0 t1 2 and t3 are local variables Here the access of shared variable x occurs inside a critical section so previous checkers would consider the program free of simple race conditions However the snapshot of x s value that is read into 70 in that critical section is used three more times The first of these uses which for pedagogic simplicity is shown here as an assign ment to 1 is justifiable a programming methodology must support using a snapshot of a shared variable outside a critical section If such a snapshot were never allowed outside a critical section then a program that printed an account balance stored in a shared variable would have to remain in the critical section while the printer put the ink on the paper But a better program would enter the critical section store a snapshot of the sha
8. ile time checker for Java We have applied the checker to several hundred thousands of lines of code and have found it to produce a small number of warnings that are nevertheless of high quality A possible improvement on our technique is to replace the boolean stale_t by a counter age_t with the following meaning Invariant J2 If from _critical_t is true then age_t is the number of critical sections that have been entered since the variable was last assigned To maintain this invariant age_t is zeroed when is assigned and incremented on each entry to a critical section When the variable is used we can then add the assertion assert from_critical_t V age_t 0 This allows the warnings to be ordered by age We suspect that warnings with higher age will be more relevant Acknowledgements We d like to thank Andrew Birrell for being dissatisfied with the fact that race condition checkers do not check for stale value errors and to Andrew 13 Marc Najork Hannes Marais and Cormac Flanagan for helping evaluate the warnings that our checker produced We d also like to thank Lyle Ramshaw for carefully reading the paper References 0 David F Bacon Robert E Strom and Ashis Tarafdar Guava A dialect of 1 2 3 4 5 6 ey ey ey ey ey Sd Java without data races In Proceedings of the 2000 ACM SIGPLAN Conference on Object Oriented Programming Systems Languages amp Applications
9. ion We have implemented our technique in a compile time checker We built the checker as an extension to the Compaq Extended Static Checker for Java ESC Java 9 11 ESC Java translates a program into a verification condition a logical formula that ide ally is valid if and only if the program is free of the kinds of errors under consideration The verification condition is then passed to an automatic theorem prover which searches for counterexamples Each counterexample is turned into a message that warns the pro grammer of a possible error in the program ESC Java performs modular checking checking one method body at a time much like a compiler performs separate compila tion The heart of ESC Java s analysis comes down to checking the validity of assertions which makes it a good engine for our stale value detection technique In this section we describe some specific considerations of our implementation and how it pertains to Java A major design consideration that we omitted from the previous section is the fact that programs have more than one lock In Java locks may be dynamically allocated and assigned so a syntactic scan of the enter_critical_section statement that acquires a lock is not in general sufficient to determine which lock is being acquired Aiming for a simple initial design our checker mostly ignores which lock is being acquired That is when in the description above we said on entry to a critical section our
10. itical_t is true just when t has received its current value inside a critical section from a shared variable We will settle for something simpler Invariant J1 from_critical_t is true if and only if the last write to t occurred inside a critical section Initially from_critical_t is false To maintain Invariant J1 we add an update of from_critical_t whenever there s an assignment to t If the assignment occurs in a critical section we add from_critical_t true GO otherwise we add from_critical_t false G1 With from_critical_t and Invariant J1 at our disposal we put the finishing touches on maintaining Invariant JO on entry to a critical section we add the following ghost statement if from_critical_t then stale_t true end G2 This maintains Invariant JO because if on entry to a critical section the last assignment to occurred in a previous critical section then the current value of t is now to be considered stale For example consider the following code fragment where x is a shared variable t is a local variable and B t is some boolean expression that mentions t enter critical_section t a exit_critical_section if B t then t 0 end enter _critical_section g t exit_critical_section Instrumenting this code according to our technique yields the following program where ghost statements are shown with comments enter _critical_section if from_critical_t then
11. lt in v getting set to the wrong element Note that this insidious error cannot be found by previous techniques because the shared variables are all accessed under the protection of an appropriate lock In summary programs can suffer from concurrency errors other than deadlocks and simple race conditions we have shown how using stale values of shared variables can also be a source of error Next we turn to the issue of how to detect such errors in programs automatically 2 Detecting stale values In the most simple and common case stale values are propagated in local variables Therefore our technique tracks the assignments to and uses of local variables We pro ceed by instrumenting the original program with some additional local variable declara tions and program statements These new declarations and statements are mechanically added to the original program To distinguish them from the original program we call the additions ghost declarations and statements Our ghost statements do not change the functional behavior of the original program except for the actions taken by a ghost assertion that fails which occurs if a possible stale value error is detected We start by introducing for every local variable in the original program a boolean ghost variable stale_t with the following meaning Invariant JO stale_t is true if and only if the value of is considered stale Note that we may have some leeway in just exactly what we co
12. nings that all of them can easily be inspected by hand Moreover the warnings produced by our tool have pointed to new errors in some otherwise well tested programs 1 Stale values In this section we give three examples The first example shows a simple race condition that previous techniques address but our technique does not The other two examples show a different kind of race condition the kind that our technique addresses A common paradigm when writing concurrent programs with shared variables is for a thread to access a shared variable only when the thread holds a designated lock When a thread acquires a lock it is said to enter a critical section it remains in the critical section while it holds the lock and it leaves the critical section when it releases the lock A critical section is also called a monitor 10 so we call this programming paradigm the monitored value paradigm The monitored value paradigm avoids simple race conditions that is the possibility of two or more threads reading and writing a shared variable at the same time which can result in data corruption The monitored value paradigm also has the nice property that it can be checked either at compile time or at runtime 13 6 8 12 As an example consider the following program where x is a shared variable and 0 and 1 are local variables enter _critical_section t0 t exit_critical_section tlh Because the first access of x occurs inside t
13. nings that indicated bugs in the code Here are brief descriptions of our test programs pachyclient is an applet to assist in reading mail mercator is a web crawler webl is the implementation of the language WebL ambit is the implementation of a language used to describe agents cluster finds groups of related web pages jigsaw is the World wide web Consortium s reference implementation web server sys man A and sys man B are proprietary programs for managing configurations of computers and peripherals We are encouraged by these results because even with no annotations we obtained fewer than 1 warning per 10 000 lines of code and yet found 4 previously unknown bugs Our prototype checker is rather slow It can check about 2000 source lines per minute The speed could be greatly improved because our prototype contains code intended for more heavy weight checking We believe that a special purpose checker could be nearly as fast as the type checker 11 5 Related work Much work and several different techniques have targeted the detection and preven tion of simple race conditions For example Warlock 13 uses static data flow tech niques ESC uses program verification techniques 6 and the Race Condition Checker for Java 8 the programming language Guava 0 and the work by Boyapati and Ri nard 3 use type checking techniques Eraser 12 and Nondeterminator 2 4 analyze dynamic executions finding races beyond those evident in
14. nother cost which agitates many users is that the checker may require users to spend time pro viding the checker with properties of the program design that otherwise are not directly The author s current address is M Burrows Google Inc Bayshore Parkway Mountain View CA 94043 USA m3b m3b google com The author s current address is K R M Leino Microsoft Research One Microsoft Way Redmond WA 98052 USA leino microsoft com evident These extra properties are typically provided by adding executable calls into the checker s run time support library or by supplying compile time annotations Previous work has studied ways of detecting or preventing race conditions where variables have not been consistently protected by locks and deadlocks In this paper we address a different kind of race condition The error can occur even when each shared variable access is correctly protected by a lock The error arises when a lock is held at the time a value is read from a shared variable but not held at the time the value is later used We don t know of any previous practical checker that detects this kind of error We present a simple checking technique for detecting these stale value errors The technique can be used with either a run time checker or a compile time checker We have built a compile time checker based on the technique We have found this checker to perform adequately to require no annotations and to produce few enough war
15. nsider to be stale Immediately preceding every read of local variable in the original program we add the following ghost assertion statement assert stale_t If this assertion fails the value stored in is considered stale and so the checker pro duces a warning To establish Invariant JO initially at the point where and stale_t are declared stale_t is set to false That is we add the ghost statement stale_t false To maintain Invariant JO we need to update stale_t in two situations when is assigned it may become fresh not stale and when the thread enters a critical section t may become stale So first stale_t needs to be updated at assignments to t A simple somewhat coarse approach is to add the ghost assignment stale_t false at every assignment t E This simple approach would treat the new value of as fresh regardless of the right hand side expression A more precise approach which we have not implemented would take E into account For example for the assignment statement t t 4 1 a more precise approach would not change the value of stale_t since the new value of t would be as stale as the previous value Second stale_t needs to be updated on entry to a critical section if s current value comes from a previous critical section then stale_t should be set to true To accomplish this we need to introduce another ghost variable from _critical_t Ideally from_cr
16. others such as the wait operation on condition variables see e g 10 2 first release a lock and then re acquire it Here is the code the for consume operation in a producer consumer application see e g 2 which uses wait to temporarily exit the critical section to yield to producers enter _critical_section a arr while n 0 wait v alneztc nezte nexte 1 mod a length n n l exit_critical_section In this example n arr and neztc are shared variables denoting the number of ele ments produced but not yet consumed a reference pointer to the array that holds those elements and the index into that array where the next element to be consumed is re spectively and a and v are local variables The code retrieves the next element to be consumed into variable v The array is used as a cyclic buffer so the increment of nextc is performed modulo the size of the array The consumer code contains an error the reference arr to the array is copied into local variable a before the wait operation and it is this copy that is used to do the array operations after the wait Hence if many producers get control during the wait call so many that some producer needs to allocate a larger array copy the elements from the previous array into the new one and update arr to point to the new array then the consumer code above will end up using the old array instead of the new one which would resu
17. r for multi threaded programs ACM Transactions on Computer Systems 15 4 391 411 November 1997 Also appears in Proceedings of the Sixteenth ACM Symposium on Operating System Principles pages 27 37 Operating System Review 31 5 1997 Nicholas Sterling Warlock a static data race analysis tool In Proceedings of the Winter 1993 USENIX Conference pages 97 106 USENIX Association January 1993 15
18. red variable into a local variable exit the critical section and then print the value from the local variable The second use of the snapshot 0 of x the assignment to 2 is more dubious This use occurs inside a critical section yet it is using the value of x from the previous time the thread was in a critical section Between the two critical sections other threads may acquire the lock and update the value of x in which case t0 is a stale copy of x Sometimes this is indeed what the programmer intended For example it may be that the program compares 0 with x to see if x has changed which may enable some optimization However one should be suspicious of such stale values because they may well have arisen from accidental uses of the wrong variable This error would be hard to catch using testing because it manifests itself only if another thread updates z between the two critical sections The third use of the snapshot t0 of x the assignment to 13 is also dubious prob ably even more so than the second use Here a code reviewer would ask Why does tO hold the snapshot of x from the first critical section why not a snapshot from the second critical section For our third example we consider the case where lock acquisitions and releases are hidden in procedure calls This is the most common way in which stale value errors occur in real programs Some procedures may for example first acquire a lock and then release it while
19. section establishes But a program verifier that supports monitors would not allow the property to be inferred in the second critical section because the value of 12 a length seen by the current thread can change arbitrarily while outside the monitor Such a program verifier would not be able to prove the access afi correct thus finding the error The Extended Static Checkers for Modula 3 6 and for Java 9 use program verifi cation technology and can find errors involving monitors and shared variables However these two checkers do not take into consideration the effects of other threads between critical sections because doing so would place an additional burden on the tool user to declare monitor invariants 10 in order to suppress otherwise spurious warnings In the design of these checkers this additional annotation burden was perceived to outweigh the benefit of finding the additional errors and thus the checkers consider only those executions where the values of shared variables remain unchanged between critical sec tions 6 11 6 Summary and future work In summary we have discussed a kind of race condition a stale value error that can arise in concurrent programs We have introduced a simple method for detecting many stale value errors The technique can be used in either a dynamic checker or a compile time checker In either case the technique does not require user annotations We have implemented the technique in a comp
20. stale_t true end G2 ti 2 stale_t false the assignment to t gives it a fresh value from_critical_t true G0 the assignment to t occurs inside a critical section exit _critical_section assert stale_t about to read B t which mentions t if B t then t 0 stale_t false the assignment to t gives it a fresh value from critical_t false G1 the assignment to t does not occur in side a critical section end enter _critical_section if from_critical_t then stale_t true end G2 assert stale_t about to read t g t 4 1 exit_critical_section Note that the ghost assertion in the second critical section will fail if the expression B t in the if statement evaluates to false This corresponds to the case where upon entry to the second critical section contains a value produced in the first critical section In other words the instrumented code has a failing assertion where the original code would have used a stale value This concludes the general description of our technique The technique can be im plemented in a dynamic checker That is by instrumenting the original program with the ghost statements above one can detect possible stale value errors through failing ghost assertions Our technique can also be implemented in a compile time checker where a warning is produced if the checker detects a possibility or certainty that a ghost assertion will fail 3 Implementat
21. the given execution Some recent work by Choi et al 5 improves precision and performance by some combination of static and dynamic techniques The meta level compilation technique in metal 7 has been used to implement checks for various locking related errors In some sense our technique is similar in flavor to some of these checks in that we search for things that look suspicious Perhaps metal would be a good framework in which to implement our technique The SLAM Toolkit 1 which uses model checking and theorem proving techniques also finds var ious locking related errors in software Our technique is complementary to these tools languages and techniques we find errors they don t and vice versa We don t know of any previous practical checker that detects stale value errors but there is a previous technique that can find them program verification For illustration consider the following program enter critical_section t a length exit_critical_section enter_critical_section s 0 1 0 while i lt t s s afi i 1 1 exit_critical_section where a is a shared variable and t s and 7 are local variables This program con tains a stale value error since the use of t occurs in a different critical section than its definition from a shared variable Our technique will find this error The loop in the second critical section relies on the invariant t lt a length which the first critical
22. these local variables would be considered stale inside the critical section of the callee we add ghost statement G2 just before evaluating the actual parameters The second implication regards return from the call Any result value of the called method is returned from within a critical section Therefore we may need to update from_critical_t if some local variable t receives a value derived from the result value of the call In particular for any assignment of an expression E to a local variable t if E contains a call toa synchronized method of the same abstraction then we add GO instead of G1 at the time is updated A final design consideration is the use of condition variables and the wait opera tion that can be applied to these The wait operation temporarily exits a critical sec tion waiting for a corresponding signal operation On return from the call to wait our checker models the re entry to the critical section by adding ghost statement G2 We mention one more fine detail that pertains to our checker When above we men tion an assignment of true to stale_t our checker actually assigns an arbitrary value to stale_t The reason for this is as follows When ESC Java encounters an assertion assert it generates a warning if E is not always true and continues checking if is not always false For the further checking downstream of this point the checker will assume E By assigning to stale_t an arbitrary value
Download Pdf Manuals
Related Search
Related Contents
Italiano User Manual ビッグオーブントースター DOT-1402 Samsung LN40C650 User's Manual Clam AntiVirus 0.80rc4 User Manual Piano sicurezza - Rete Civica di Trieste PM2.5*測定用サンプラ Copyright © All rights reserved.
Failed to retrieve file