Writing security code: Beware of volatile atomic misconceptions

Source: Internet
Author: User

This article copyleft [email protected] all, using the GPL published, can be freely copied, reproduced. But reproduced please maintain the integrity of the document, stating the original author and the original link, strictly prohibited for any commercial use.======================================================================================================The description of volatile is a commonplace issue. The definition of volatile is simple, which is understood to be variable and prevents the compiler from optimizing it. Then the use of the following three kinds of general:1. External device register-mapped memory-because the external device registers may change due to the state of the external device, the mapped memory needs to be marked as volatile;2. Global variables for multi-threaded or asynchronous access;3. Embedded assembly-prevents the compiler from optimizing it; The first and third of these three uses are generally not in doubt. But with regard to the second use, there are always friends who misunderstand it.   first of all, when is the global variable required to have a volatile modifier? For example, if most of our global variables are lock-protected, do we still need volatile? The answer is no, that is, when a global variable is protected by a lock, the global variable does not need to be volatile. There are two reasons: one is that the lock guarantees the serial of the critical section, and the other is the memory barrier in the implementation of the lock, which guarantees that the critical section accesses the global variable to the newest value. It can be concluded, then, that a global variable with no lock protection needs to be modified with a volatile one, as in the following scenario: 1. global variable int exit_flag = 0;2. The exit condition for the main loop of thread 1 is to check if Exit_flag is 1 and 1, then exit the main loop; 3. Thread 2 In some cases, modify exit_flag to 1.In addition, if it is asynchronous, there is no thread 2, and there is a signal processing function that assigns a value of Exit_flag to 1 when the specified signal is received. At this point, exit_flag need to be modified using volatile. Otherwise, for thread 1 code, if the compiler discovers that there is no place to modify Exit_flag in line 1 code, it is possible to put Exit_flag in the register cache. In this way, every time the condition is checked, it is read from the register, not the exit_flag corresponding memory. This results in a value of 0 per read, which causes Thread1 to fail to exit. Using the volatile modifier exit_flag avoids this optimization by the compiler, forcing each read to be read from memory, which ensures that THREAD1 can read to the latest value and exit when Exit_flag is set to 1 o'clock. So now there's a problem. When there is a global variable volatile int counter = 0 as a counter, and two threads will modify this counter at the same time, does this counter require lock protection? For example, the following code:
    1. static volatile int counter = 0;
    2. void Add_counter (void)
    3. {
    4. ++counter;
    5. }
in a multi-threaded environment, is it safe? is the increment of counter the result we expect? Please think for a minute first! To get the answer, let's look at the assembly code:
    1. Add_counter:
    2. PUSHL%EBP
    3. MOVL%esp,%EBP
    4. MOVL counter,%eax
    5. Addl $,%eax
    6. MOVL%eax, counter
    7. POPL%EBP
    8. Ret
look at these three lines in red. What's going on? Why do you put the counter into the register EAX first, and then the EAX to operate, and then eax into counter. In that case, the++counter will never be atomic! Must be protected by a lock!  Let's see why the assembly is such a behavior. What kind of service does volatile provide?! first modify the previous C code:
    1. static int counter = 0;
    2. void Add_counter (void)
    3. {
    4. for (; Counter! = 0x10; ++counter) {
    5. ++counter;
    6. }
    7. }
then look at its assembly code, remember to use the-O optimization ah. [email protected] test]$ gcc-s-o test.c
    1. Add_counter:
    2. PUSHL%EBP
    3. MOVL%esp,%EBP
    4. MOVL counter,%eax
    5. Cmpl $16,%eax
    6. JE. L4
    7. . L5:
    8. Addl,%eax
    9. Cmpl $16,%eax
    10. Jne. L5
    11. MOVL%eax, counter
    12. . L4:
    13. POPL%EBP
    14. Ret
from the assembly code above, it is clear that the value of the counter is stored in eax, then 2 is added to eax each time, and then used to compare EAX with 16 to complete the work of the For loop in C code.  Add the volatile modifier to counter below
    1. static volatile int counter = 0;
    2. void Add_counter (void)
    3. {
    4. for (; Counter! = 0x10; ++counter) {
    5. ++counter;
    6. }
    7. }
still open the compiler's optimization switch[email protected] test]$ gcc-s-o test.c
  1. Add_counter:
  2. PUSHL%EBP
  3. MOVL%esp,%EBP
  4. MOVL counter,%eax
  5. Cmpl $16,%eax
  6. JE. L4
  7. . L5:
  8. MOVL counter,%eax
  9. Addl $,%eax
  10. MOVL%eax, counter
  11. MOVL counter,%eax
  12. Addl $,%eax
  13. MOVL%eax, counter
  14. MOVL counter,%eax
  15. Cmpl $16,%eax
  16. Jne. L5
  17. . L4:
  18. POPL%EBP
  19. Ret
The L5 is implemented for the assembly corresponding to the for loop in the C code. By comparing the previous assembly, it is easy to find the difference. Although the counter increment is performed, both use the register EAX. However, each time the counter is accessed, the former will use the register EAX directly, while the latter (when using volatile) will re-read the latest value from counter to EAX and then use EAX.  OK. Now the volatile situation is clear. Volatile provides only guaranteed access to the variable, each time it reads the latest value from memory and does not use the register to cache the value-each time it is read from memory. In the modification of the variable, volatile does not provide a guarantee of atomicity. So whether the compiler is directly modifying the memory value or using a register modification is a volatile definition. So, in a word, volatile does not provide a guarantee of atomicity.

Writing security code: Beware of volatile atomic misconceptions

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.