简体   繁体   中英

Could a brute-force algorithm cause a stack overflow? (recursion)

So let's say we have a recursive brute-force function.
(I especially wondering about brute-force functions because they can easily call themselves a million times recursively.)
Like this, for example:

function BruteForce(chars, min, max, prefix, stage) {
    for (var i = 0, len = chars.length; i < len; i++) {
        if (stage >= min-1)
            console.log(prefix + chars[i])
        if (stage < max-1)
            BruteForce(chars, min, max, prefix + chars[i], stage+1)
   }
}

BruteForce("abc", 1, 5, "", 0)

(Consider this pseudo code for now, as my question isn't about JavaScript only.)

Wouldn't a function like that fill the stack with new arguments until it overflows?

What would happen if you'd execute something like that in C/C++ and the like?
Does the calling convention matter? How well would the different calling conventions be able to handle this?

And why doesn't the JavaScript code above cause a stack overflow or so?

What would happen if you execute something like that in C/C++ and the like? You would simply get a stack overflow. The terminal will output a error message related to it. Note that the program will correctly execute till a point, and then the stack overflow error will be thrown, and execution will abruptly terminate.

Why doesn't the Javascript code cause a stack overflow? I have no prior experience with javascript, but the reason appear to be simply that the stack hasn't overflowed yet. If you had a deep enough recursion, the stack should overflow. To test this, why not initialise start as 0 and set max as 10^9 . The one case where recursion may not cause a stack overflow is that if the language doesn't use the stack for function recursion.

The JavaScript code wouldn't cause a stack overflow. Being a Garbage Collected language, everything is placed on the heap. Now it is possible that eventually the heap will hit the stack, and cause a problem. But nowadays the heap can be so big that it will probably never happen, unlike the stack which is always limited.

Let's try to answer your questions one by one:

Wouldn't a function like that fill the stack with new arguments until it overflows?

Under some circumstances yes. It depends on the arguments themselves and how the stack is handled, which is very implementation-dependent.

What would happen if you'd execute something like that in C/C++ and the like?

In general, C/C++ don't provide much in the way of "stack handling". Stack overflow is undefined behaviour.

On embedded systems, you basically allocate some memory to the stack and if you overflow it... well, you keep writing over some other part of memory (heap, static data...). Eventually, you will run out of available memory, and what happens then depends on the CPU and your runtime - a crash, stall, or some such thing.

On a hosted system (Windows, POSIX...), stack overflow will probably involve a page fault exception, which may prompt the runtime to allocate new pages and add them to the stack, if possible. But, only if your runtime works like that, it might as well behave like an embedded system, or simply not handle the page fault (thus your program will crash).

Does the calling convention matter? How well would the different calling conventions be able to handle this?

Not much, as this pretty much has to use a calling convention that puts arguments on the stack. Which is first and which is last doesn't really matter (neither does do you put an underscore before the name of the function). A "register" calling convention ("fast call" or whatever your compiler calls it) will either be ignored for a recursive function, or simply the parameters will be put on stack, then copied to registers and then the function will start.

Even on sliding register window CPUs (like SPARC), it won't matter, as the register window is mostly shallow, and you will again get back to using the stack.

And why doesn't the JavaScript code above cause a stack overflow or so?

AFAICT, the code above doesn't have a very deep stack "nesting" (you "nest" as high as max and it is 5 ), and since pretty much anything in Javascript is an int, double or pointer (from a low-level memory POV), your five parameters don't occupy much memory (probably ~40 bytes). Now, if you would to increase the max to something like 2^31 , I'm guessing there could be trouble. :)

Also, keep in mind that a Javascript interpreter may do funky things, like figure out that you never change chars , min or max and simply don't put them on a stack each time (thus saving space). In theory, even C/C++ compiler might do that, but only as a part of some "Whole program optimization".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM