Please answer a question about automatic stack extension for UNIX/Linux, unixstack

Source: Internet
Author: User

Please answer a question about automatic stack extension for UNIX/Linux, unixstack

If you have the skills, you can be a zombie if you have no skills!

If you want me to answer questions about the process stack and thread stack, as long as the questions are not general and the questions are clear, I will answer them one by one, with a accuracy rate of nine. However, sadly, the problem is often not very specific, so the game is over !! . But if you give me a chance to ask, I will ask the following question. Remember to give it a try (this is rough enough! Don't take it seriously. The important things are as follows -):

The UNIX/Linux stack is extended in most platforms (note that I have already told the truth and I have not asked... how is it extended? This can be recited and read out.) in an execution stream, A function A is called, this function A allocates A large array on the stack, leading to the stack extension (note, this is another statement, and I haven't given A problem yet). Then A returns, in UNIX/Linux, the large array in A should be recycled to allocate the stack space-because it is no longer used, but it does not (this may be A trap, it's really UNIX/Linux that should have done this, but it's not done, or I'm just teasing you... not sure, but the statement is true ). (Note, my question is coming.) Why does UNIX/Linux do this ???!!!
All answers such as those specified by the operating system are zero points! Besides, can you prove that I'm right? What if I want to tease you? Can the operating system specify an error? Or I can continue to ask why, until I have been asked by my junior high school history teacher, as if I could find some sense of pleasure, let's try it! The problem is that no matter whether the problem is a pseudo proposition or you have your own ideas, you can say five minutes. I think it is enough. The answer requirements for this question are as follows:
Time Limit: 5 minutes.
Answer Method: full oral, no drawing, no gestures... ambiguous language, poor expression ability, and incorrect calculation.
Suggestion: if you have no in-depth understanding of OS Virtual Memory Management and Linux VMA implementation details, do not guess the answer. Please directly answer "do not know" and read this article.
.................................
5 minutes later. I want to publish some of my ideas.
First, there is a problem in itself. Because Linux should do this, But it:
First, it may not be possible;
Second, it is not necessary at all.
So what is the argument? Why?
It is unnecessary to make positive arguments. The execution stream will also call other functions or call A again to frequently recycle stack loss performance;
Negative arguments are hard or hard to achieve. The stack operation is controlled by the processor, and there is no synchronization mechanism between it and the OS Kernel address space management mechanism. After a function call is completed, the CPU automatically handles the stack register contraction and the stack frame pops up, however, it cannot notify the OS Memory Management System to update the ing relationship of the process address space.
How to deal with the disputes in the address space region where the stack is located. The stack will be extended to address B when an exception occurs. B may be a readonly address or a protective hole. When the stack is extended down, if address B is on the top, the stack space will be reduced. If address B is off, even if function local variables are almost full of the space from the bottom of the stack to Space B, mmap can unmap this area and then remap, however, this can cause data confusion and serious problems.
Conclusion: During the mmap or brk process, compare the top of the stack with the esp register. If it is smaller than the top of the stack, It is recycled (equivalent to normal, as big as impossible ).
Linux has no esp register. The principle of Linux is simple. If an address is in the range of vma or the stack can be expanded and has permissions, it is accessible. The kernel is controlled by the application, regardless of whether the VMA belongs to a stack, heap, or anything. That is to say, you can write a piece of code, clearing all the areas in the address space that can be written is completely possible. Buffer overflow may be a deliberate destruction, but accidental errors may also cause damage to the programmer, although most of them do not know how errors occur. I don't want to give a long story about how Linux manages VMA. You know this is a prerequisite and you must know it. I used a piece of code and two diagrams to show how the Linux kernel manages address space ing near the stack, and in the second figure, if you have to deliberately destroy, what problems will it cause. That is to say, once an inexplicable error occurs, you must be able to understand in detail how this error occurs.
DEMO code
# Include <stdio. h> # include <stdlib. h> # include <sys/types. h> # include <unistd. h> # include <sys/mman. h> # define LARGE 70000000 # define PAGESIZE 4096 // This function does nothing, just to extend the stack downward // please note that the stack size limit is removed with ulimit, this will make it easier to describe the problem void call () {int I; char a [LARGE]; // believe that segfault must be triggered in the intermediate value assignment, because the elements on both sides are either in the stack/fixmap vma, // is either in the free and lonely vma that is intercepted by fixmap. Therefore, the following assignment will not cause a segment error: // a [0] = 1; // a [LARGE-1] = 1; for (I = 0; I <LARGE; I ++) {a [I] = 1 ;}} int main (int argc, char ** argv) {int I; char * p_map, * p_base, * p_base2; printf ("% d \ ninit state \ n", getpid (); // obtain the approximate address of the stack, and the PAGESIZE is aligned. P_base = (char *) & I; p_base2 = (char *) (unsigned long) p_base )&~ 4095); // obtain the address that is aligned with pagesize for fixmap. The starting point of this address is under the current stack. P_base2 = (char *) (unsigned long) p_base2-(unsigned long) 36 * PAGESIZE); getchar (); // call fixmap, apparently, if you carefully analyzed the/proc/xx/maps file during getchar and obtained the above magic number, the following mmap will succeed in any case! P_map = (char *) mmap (void *) p_base2, PAGESIZE * 3, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,-1, 0 ); if (p_map = MAP_FAILED) {printf ("failed 1 \ n");} else {printf ("before unmap fixmap around stack \ n"); getchar (); // if it succeeds, it will be released. At this time, the address space will be restored to munmap (p_map, PAGESIZE * 3) before mmap );} printf ("after unmap fixmap around stack \ n"); getchar (); call (); printf ("after extend stack [first] \ n "); Getchar (); // still call the same mmap for fixmap. The call is called, and the stack // space has been extended to the fixaddress of the fixmap. Unfortunately, the call is successful, however, it splits stack vma // into two segments. In any case, the access can still be performed. P_map = (char *) mmap (void *) p_base2, PAGESIZE * 3, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,-1, 0 ); if (p_map = MAP_FAILED) {printf ("failed 2 \ n");} printf ("after second fixmap around stack at the same address \ n"); getchar (); // This is even worse! Some unmap the above fixmap vma and leave a void. Munmap (p_map, PAGESIZE); printf ("after unmap fixmap around stack incompletely \ n"); getchar (); // stack extend is not triggered when the cavity is touched! Instead, segfault! Explosion! Call (); // never arrive here! Printf ("after extend stack [second] \ n"); getchar (); return 0 ;}

The following figure illustrates how the address space ing area near the stack of the process evolves until an accident occurs:




The following figure shows the accident process and the cause:




If you think that the picture is drawn by myself, you must have a question: What did I draw? In fact, I did not draw it by looking at the code, by constantly viewing the maps file of procfs, I learned the details of the process's address space in real time and converted it into the figure above. In order to give me the opportunity to query the maps file on another terminal, I added the getchar call in the Code. After each view of the maps file, I will take a keyboard return key. My tests are as follows:
Process output after code compilation Root @ abcd :~ #./A. out
7846
Init state

Before unmap fixmap around stack

After unmap fixmap around stack

After extend stack [first]

After second fixmap around stack at the same address

After unmap fixmap around stack incompletely

Segment error (core dumped)
View the output of the maps file of each process: Root @ abcd :~ # Cat/proc/'ps-e | grep a. out | awk '{print $1} ''/maps | tail-n 6 | head-n 4
2b2c01483000-2b2c01487000 r -- p 00157000 fe: 00 387296/lib/libc-2.11.2.so
2b2c01487000-2b2c01488000 rw-p 0015b000 fe: 00 387296/lib/libc-2.11.2.so
2b2c01488000-2b2c0148f000 rw-p 00000000 00: 00 0
7fff6236a000-7fff6237f000 rw-p 00000000 0 [stack]
Root @ abcd :~ # Cat/proc/'ps-e | grep a. out | awk '{print $1} ''/maps | tail-n 6 | head-n 4
2b2c01487000-2b2c01488000 rw-p 0015b000 fe: 00 387296/lib/libc-2.11.2.so
2b2c01488000-2b2c0148f000 rw-p 00000000 00: 00 0
7fff62359000-7fff6235c000 rw-p 00000000 00:00 0
7fff6236a000-7fff6237f000 rw-p 00000000 0 [stack]
Root @ abcd :~ # Cat/proc/'ps-e | grep a. out | awk '{print $1} ''/maps | tail-n 6 | head-n 4
2b2c01483000-2b2c01487000 r -- p 00157000 fe: 00 387296/lib/libc-2.11.2.so
2b2c01487000-2b2c01488000 rw-p 0015b000 fe: 00 387296/lib/libc-2.11.2.so
2b2c01488000-2b2c0148f000 rw-p 00000000 00: 00 0
7fff6236a000-7fff6237f000 rw-p 00000000 0 [stack]
Root @ abcd :~ # Cat/proc/'ps-e | grep a. out | awk '{print $1} ''/maps | tail-n 6 | head-n 4
2b2c01483000-2b2c01487000 r -- p 00157000 fe: 00 387296/lib/libc-2.11.2.so
2b2c01487000-2b2c01488000 rw-p 0015b000 fe: 00 387296/lib/libc-2.11.2.so
2b2c01488000-2b2c0148f000 rw-p 00000000 00: 00 0
7fff5e0bb000-7fff6237f000 rw-p 00000000 0 [stack]
Root @ abcd :~ # Cat/proc/'ps-e | grep a. out | awk '{print $1} ''/maps | tail-n 6 | head-n 4
2b2c01488000-2b2c0148f000 rw-p 00000000 00: 00 0
7fff5e0bb000-7fff62359000 rw-p 00000000 00:00 0
7fff62359000-7fff6235c000 rw-p 00000000 00:00 0
7fff6235d000-7fff6237f000 rw-p 00000000 0 [stack]
Root @ abcd :~ # Cat/proc/'ps-e | grep a. out | awk '{print $1} ''/maps | tail-n 6 | head-n 4
2b2c01488000-2b2c0148f000 rw-p 00000000 00: 00 0
7fff5e0bb000-7fff62359000 rw-p 00000000 00:00 0
7fff6235a000-7fff6235c000 rw-p 00000000 00:00 0
7fff6235d000-7fff6237f000 rw-p 00000000 0 [stack]
I am afraid that the text above is too messy and the format may be problematic in different browsers. I also specially cut a picture:




What is the use of this method to completely limit the size of a process's stack? If the stack is out of bounds, it is not an error, but A segfault. Then you can capture the segfault in signal, and drop the fixmap vma of the incomplete unmap and the poor and lonely incomplete stack vma to the complete unmap. But this is really not fun. What is the purpose? Its role is to give you a better understanding of how Linux manages virtual address spaces.

Small Tips this article does not involve the thread stack, but it is not difficult, the thread stack is generally dynamically allocated in the heap area or in the middle of the large mmap area, mmap To Give It A MAP_GROWSDOWN mark. There is no difference in its management methods. The core issue is how the page missing exception handling program identifies A missing page is a missing page in vma (the result is page adjustment) or a missing page outside vma. In the latter case, the page missing processing logic should further identify whether the page is missing from the stack (the result is the extend stack and then the page is adjusted), or whether the page is not missing from the stack (the result is segfault ...).
Linux stack is always extended unless it encounters a run contract in this way described in this article. If you want to read the Linux kernel code, you also need to understand the following facts:
1. The find_vma function has only one limit for finding vma, that is, the input address must be smaller than the end of vma. Not many people think that the input address must be between start and end of vma;
2. The find_vma function is implemented in this way incompletely, because it is designed to simplify the process of page disconnection and provide a more unified way to simultaneously process upgrows and downgrows vma.

Although this question is a bit messy, if you can find the above answer for five consecutive minutes, it should be true! However, I don't know how to express myself. I don't need to explain every detail in the above Code. In short, I think this question is a good question. We recommend that you give this article an interview question. If you cannot discover the problem or make it impossible, do not! This is really a good test question. It is so good that I want to come up with a few more times better than it.

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.