Thread: Can it be detected if stack space is about to expire?

  1. #31
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by King Mir View Post
    Why? You're only ever popping or pushing
    Which is exactly why a dequeue or vector is overkill. You never need to index the stack. You might need to look into the stack for outer scopes, but this is just done by following the pointers.

    The machine stack is also a linked list. It happens to be allocated contiguously down the stack memory. But unless you're omitting frame pointers, the frames on the stack are literally a linked list, and you can walk them exactly that way.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  2. #32
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    The program stack is a continuous memory array, which is a boon, because it doesn't have to allocate memory for each function call. It has frame pointers, because it has variable size frames. But that's not needed for storing the same kind of object.

    Both deques and lists have constant time insertion and deletion for the last element, but the per element memory overhead of a linked list is more. If a deque doesn't store a pointer to the last element, which it likely does, it's because the extra derefeence + index is nothing to fuss over. With a list, every time an element is added, the system has to reserve memory for it, which takes more than a few dereferences. A deque will preallocate a large chunk, and only increment the number of elements, untill that chunk runs out. Then it will add another chunk, but unlike a vector it won't copy the old elements into the new chunk. This also helps with chacheing and especially paging (though that's less of an issue these days), because recently pushed and popped elements in a row will be adjacent in memory. Of course that last benefit applies to some cases more than others; in this case it would benefit the parse stack, but probably not the function stack, especially because a map is itself a complex object.

    Deques are the way to go for arbitrary size stacks and queues. For small sizes a vector works better for a stack, and a circular buffer works better for a queue.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  3. #33
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by manasij7479 View Post
    Well.. as the manual popping takes place almost at the end of the scope here, and the map I'm pushing into it is itself local and not dynamically allocated, I think it is guaranteed.
    Did you mean something else?
    What happens if an exception is thrown? The pop function is never called.

    Quote Originally Posted by whiteflags View Post
    Well that was unhelpful of you. I assume you mean it isn't exception safe because of how new_local is written.

    Couldn't you just catch the exception, release anything that needs to be destroyed and then rethrow?
    But mana isn't doing that. Hence, it is not exception safe.
    It is possible to do as you say, but that is a hack and a mess, and is no different from Java.
    You have to somehow determine where the exception occurred and fix up that mess before re-throwing an exception.
    It is completely against the idea of RAII.

    Quote Originally Posted by King Mir View Post
    You don't necessarily want to pop something off on an exception. An exception would mean something is wrong with the interpreter. The state of the interpreted program stack should probably be left alone, to allow backtracing and better logging.

    An exception in user code is a different story, but that shouldn't trigger an actual exception.
    I'd say that in such cases, an exception should be thrown with enough information to actually log the error (example, state of the stack).
    Not cleaning up after an exception is irresponsible and leaves a mess. It also leads to bugs later on if you somehow need to restart the operation that failed.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #34
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    >What happens if an exception is thrown? The pop function is never called.
    It isn't meant to be called there.
    Depending on the exception, the program would offer the user to correct the input (Common Lisp does it...but it'd take some time for me to implement all that)
    And ..if the user just decides to forget the old input and start a new one.. all the necessary popping will be done by the catch.

  5. #35
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    A dangerous approach.
    Ideally, each function should clean up after itself. Otherwise it will lead to bugs.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #36
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Elysia View Post
    But mana isn't doing that. Hence, it is not exception safe.
    You didn't even clear up for me where the exception problem is.

    It is possible to do as you say, but that is a hack and a mess, and is no different from Java.
    What makes you say that. try catch is the way to deal with exceptions, apart from just not catching them at all.

    You have to somehow determine where the exception occurred and fix up that mess before re-throwing an exception.
    This is what confuses me even more. How many different exception errors do you even see? The only error I can see is bad_alloc, and the only one this function should maybe handle. And I'm not even sure about that. I thought that when exceptions where thrown, things go out of scope normally. It's only when you have to manually release memory that it's a problem.

    It is completely against the idea of RAII.
    How do you figure? malloc and free can be used in accordance with the RAII idiom as can push and pop, or constructors and destructors.

  7. #37
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by whiteflags View Post
    You didn't even clear up for me where the exception problem is.
    If it isn't obvious, it's the manual popping. Any manual cleaning up or "undo action" is an exception problem because those statements will be skipped when an exception is thrown.

    What makes you say that. try catch is the way to deal with exceptions, apart from just not catching them at all.
    Consider this:
    Code:
    try
    {
    	int * p = new int;
    	function_that_can_throw(p);
    	std::cout << *p << std::endl;
    }
    catch (const std::exception& ex)
    {
    	std::cout << "Oops, something went wrong!\n";
    }
    If an exception is thrown, p is leaked. In Java, you have to declare p outside the try block and check if p isn't null, and if so, release it (that is assuming p is some resource, like say, a database).
    Now scale that up. Add more statements and more paths and you will yourself having to add a lot of code in every function to properly clean up and re-throw.
    Clearly, this is not desirable and it costs its fair share of cpu time.
    Ideally, we'd like for every function to just clean up after itself so we don't have to do it manually.

    This is what confuses me even more. How many different exception errors do you even see? The only error I can see is bad_alloc, and the only one this function should maybe handle. And I'm not even sure about that. I thought that when exceptions where thrown, things go out of scope normally. It's only when you have to manually release memory that it's a problem.
    But if you push something that requires a manual pop, that pop never gets done, does it? Hence the problem.

    How do you figure? malloc and free can be used in accordance with the RAII idiom as can push and pop, or constructors and destructors.
    Yes, if you do it properly. Clean up after yourself in the destructor and you've got RAII. Do it manually and you don't have the RAII idom.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #38
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    But if you push something that requires a manual pop, that pop never gets done, does it? Hence the problem.
    Except it doesn't require a manual pop. Maybe I'm just too stupid for the conversation, but the whole scope object would be destroyed eventually if you never caught the exception. If you did catch the exception somewhere, I don't think that var_scope is out of scope -- in fact it's declared elsewhere and not local to the function we are talking about. That means you could pop when you catch. And it doesn't have the problem you illustrated with your example.

    In Java, you have to declare p outside the try block and check if p isn't null,
    And in C++ you don't!
    Code:
    int* p = nullptr;
    try
    {
         p = new int;
        function_that_can_throw(p);
        std::cout << *p << std::endl;
    }
    catch (const std::exception& ex)
    {
        delete p;
        std::cout << "Oops, something went wrong!\n";
    }
    Safe.

  9. #39
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by whiteflags View Post
    Except it doesn't require a manual pop. Maybe I'm just too stupid for the conversation, but the whole scope object would be destroyed eventually if you never caught the exception. If you did catch the exception somewhere, I don't think that var_scope is out of scope -- in fact it's declared elsewhere and not local to the function we are talking about. That means you could pop when you catch. And it doesn't have the problem you illustrated with your example.
    But mana doesn't catch and rethrow. It is one possible solution.
    A better solution is to force a pop when the object goes out of scope.

    And in C++ you don't!
    I would write it as:
    Code:
    try
    {
    	std::unique_ptr<int> p = new int;
    	function_that_can_throw(p);
    	std::cout << *p << std::endl;
    }
    catch (const std::exception& ex)
    {
    	std::cout << "Oops, something went wrong!\n";
    }
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #40
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    Quote Originally Posted by whiteflags View Post
    Code:
    int* p = nullptr;
    try
    {
         p = new int;
        function_that_can_throw(p);
        std::cout << *p << std::endl;
    }
    catch (const std::exception& ex)
    {
        delete p;
        std::cout << "Oops, something went wrong!\n";
    }
    Safe.
    That is 'almost' what I was aiming to do... (Instead of deleting, I'd be popping values from a global stack).

  11. #41
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Elysia View Post
    I would write it as:
    Good for you. But in relation to your earlier post however, the key difference is that delete on null is safe. It isn't like Java in that sense. If I went and used the STL I wonder if I could have still made that point at all, or if you'd've replied with another problem... like me straying from the example that you wrote.

  12. #42
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The point was that if that was Java, and p was a database, then you'd have to do

    if (p) p.Release();

    For that matter, how do we even know that the state of p is well-defined at the catch block? The exception can happen anywhere.
    So we have to poll and figure out WTH happened so we can undo it. That's just a pain.
    And we have to do it in every local function.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #43
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    So we have to poll and figure out WTH happened so we can undo it. That's just a pain.
    And we have to do it in every local function.
    Again the only exception I see possible with scope is bad_alloc... and it's a global object so in general it's a pain and things will happen in every local function (emphasis yours)... Is it still inappropriate to catch that error associated with the stack of an interpreter in something important, like main()?

    I don't really want to talk about this anymore. But try and keep in mind the actual job at hand. It's like you want to lecture me on the general case.

  14. #44
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by whiteflags View Post
    Again the only exception I see possible with scope is bad_alloc... and it's a global object so in general it's a pain and things will happen in every local function (emphasis yours)... Is it still inappropriate to catch that error associated with the stack of an interpreter in something important, like main()?
    If you don't want to talk about it, that's fine. But let me just clear up that.
    It's not about catching it in main--obviously you will want to--but about what happens in the functions as the stack unwinds.
    Will the object end up in some inconsistent state because you fail to pop the scopes? If so, how do you deal with that?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #45
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by manasij7479 View Post
    That is 'almost' what I was aiming to do... (Instead of deleting, I'd be popping values from a global stack).
    I'd say that's fine, especially if you might pop different amounts of data during error recovery.

    Though you should probably have (at least) two stacks, one for tokens, and one for function call data. I get the impression that you don't.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Stack Smashing Detected
    By halexh in forum C Programming
    Replies: 13
    Last Post: 05-19-2010, 02:10 AM
  2. *** stack smashing detected ***
    By chakra in forum C Programming
    Replies: 2
    Last Post: 06-09-2009, 09:12 PM
  3. *** stack smashing detected ***
    By Martin_HS in forum C Programming
    Replies: 9
    Last Post: 05-29-2009, 04:01 AM
  4. help on *** stack smashing detected ***
    By jodelson in forum C Programming
    Replies: 8
    Last Post: 08-16-2007, 06:25 PM
  5. Managing Stack space?
    By Aidman in forum C++ Programming
    Replies: 4
    Last Post: 09-07-2003, 02:29 PM