Thread: Memory mgmt and g++

  1. #1
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196

    Memory mgmt and g++

    Hey,

    I think I may be losing it...so I'm coming here...

    I was playing with the snippets plugin in gedit (if you don't know what that is it doesn't matter) and just made a program using them..

    The program works, fine. If I'm not mistaken, this program should blow up...but it doesn't. What gives?

    Code:
    #include "test.h"
    
    
    int main (int argc, char const* argv[])
    {
        if (1 == 1)
        {
            MyClass* a;
            int* b;
            *b = 5;
            a->myfunct();
            printf("%i\n", *b);
            delete a;
        }
    
        return 0;
    }
    Code:
    #include <stdio.h>
    
    class MyClass
    {
        public:
            MyClass();
            virtual ~MyClass();
    
            void myfunct()
            {
                printf("Hello World\n");
            }
    
        private:
    };
    Output:
    Code:
    $ ./a.out 
    Hello World
    5
    One word: HOW? It's like creating the pointers are allocating the memory...what gives?

    This is being compiled with g++ version 4.4.3.

    I need somebody to tell me I'm not losing myself here...

  2. #2
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Behavior: undefined.

    That is the official answer. The unmanaged C++ implies that somethings simply can be undefined you don't know what happens so bad and unpredictable things might happen if you are not careful. Did you complile with -Wall or even -Wextra? If not try this to see the warnings

    But lets think how is this possible.
    Code:
    int* b;
    *b = 5;
    So b points somewhere in Texas. Lets say Austin. So you give Austin the value 5. Then you print it. No harm done. "But I haven't allocated any memory?". True, but memory exists, it just isn't safely/properly allocated. So b might be pointing on another variables memory for example and the program won't crash since you are writing/reading on an allowed place.

    This:
    Code:
    a->myfunct();
    again might be possible because myfunct() just prints something constant. So it points on a memory address which contains the myfunct commands. Like:
    Code:
    myfunct:
    ...
    ...
    RET
    this exists since MyClass exists.

    Finally:
    Code:
    delete a;
    who knows what happens here exactly?

    All these assume a certain implementation, can be affected by some optimizations etc etc and practically there is no sense trying to figure out why you don't get an error. You might get an error when you restart your computer for example.
    The point is that the behavior is undefined and most importantly wrong. And this is why C++ is considered "unsafe" compared to a managed language like Java.

  3. #3
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by C_ntua View Post
    Behavior: undefined.

    That is the official answer. The unmanaged C++ implies that somethings simply can be undefined you don't know what happens so bad and unpredictable things might happen if you are not careful. Did you complile with -Wall or even -Wextra? If not try this to see the warnings
    Yeah, I get that it's undefined behavior, but if I never allocated space for it, especially that object, with most compilers it would typically crash...

    With warn all on, it tells me they're not defined (a and b) - they seem very much defined. It's almost too defined for undefined behavior...

    Quote Originally Posted by C_ntua View Post
    But lets think how is this possible.
    Code:
    int* b;
    *b = 5;
    So b points somewhere in Texas. Lets say Austin. So you give Austin the value 5. Then you print it. No harm done. "But I haven't allocated any memory?". True, but memory exists, it just isn't safely/properly allocated. So b might be pointing on another variables memory for example and the program won't crash since you are writing/reading on an allowed place.
    Yeah, I get that B can randomly point in memory that randomly happens to be in your memory space...I know it's not defined and you cannot rely on it, but typically a pointer is initialized to 0...I know you can't rely on it, but typically it is. Some random place in your memory space that doesn't cause issues? That's a bit too random for me to be ok with...

    Quote Originally Posted by C_ntua View Post
    This:
    Code:
    a->myfunct();
    again might be possible because myfunct() just prints something constant. So it points on a memory address which contains the myfunct commands. Like:
    Code:
    myfunct:
    ...
    ...
    RET
    this exists since MyClass exists.
    This is true. Fair enough, so I said, okay, let me make the function take an int, so an int HAS to be loaded into a register before it jumps to the function label.

    Then I said: Well wait a moment, what if the compiler optimization is SO GOOD, that it knows it's a hard coded int, it knows the pointer is pointing there, it knows where it can be found, what if it resolves the int arg at compile time? While that's a ridiculous amount for a compiler to be able to do, I passed the int in as a command line parameter, so it can't be determined until runtime, the result?
    Code:
    $ ./a.out 2
    Hello World 2
    5
    I know what undefined behavior is..this isn't it :-\.

    Quote Originally Posted by C_ntua View Post
    Finally:
    Code:
    delete a;
    who knows what happens here exactly?

    All these assume a certain implementation, can be affected by some optimizations etc etc and practically there is no sense trying to figure out why you don't get an error. You might get an error when you restart your computer for example.
    The point is that the behavior is undefined and most importantly wrong. And this is why C++ is considered "unsafe" compared to a managed language like Java.
    Yeah, I get what undefined behavior is, and I get that I shouldn't waste my time trying to figure out why it's not failing because of it. But this behavior seems VERY defined, it's very much so just as if memory was allocated when I created those pointers, and under NO circumstances, should a C/C++ compiler do something that drastic.. I'm going to look at the assembly code it compiles, to make sure there's no calls to the allocator.

  4. #4
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Well I ran it to assembly code (not compiled) and took a looksie..

    The asm looks innocent as hell, nothing unexpected, no calls to the allocator, everything looks as it should.. I don't think gcc does any optimization to assembly code from here...

    Guess it's all just a really nasty coincidence...looks way too neat for my liking, though :-\.

    EDIT:
    Not trying to change topic, I know this is out of the scope of this forum too, but does anybody know what these asm directives are:
    Code:
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    I've never seen anything like that before..
    Last edited by Syndacate; 02-26-2011 at 03:04 AM.

  5. #5
    C++ Junkie Mozza314's Avatar
    Join Date
    Jan 2011
    Location
    Australia
    Posts
    174
    Quote Originally Posted by C_ntua View Post
    And this is why C++ is considered "unsafe" compared to a managed language like Java.
    Do I detect a hint of bias here? :-P

    I like that C++ gives you control over how you want to manage the memory. If there's memory you don't want to pay attention to, you can always use boost::shared_ptr or something like it.

  6. #6
    Nasal Demon Xupicor's Avatar
    Join Date
    Sep 2010
    Location
    Poland
    Posts
    179
    I know what undefined behavior is..this isn't it :-\.
    Well, even if the consequences of UB are that it seems to work fine, it doesn't make it any "less undefined" or "more defined". Anything can happen, it can even work as expected, it doesn't make it right though.

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    But this behavior seems VERY defined, it's very much so just as if memory was allocated when I created those pointers, and under NO circumstances, should a C/C++ compiler do something that drastic.. I'm going to look at the assembly code it compiles, to make sure there's no calls to the allocator.
    Why would it need to use an allocator? Sometimes pointers point to other memory sections than the heap. const char* is an exellent example.

    I'm thinking that b's value is just the same as the address of the literal 5 which would be in the data section (I think). Especially after this:

    *b = 5;

    You could use it in a read-only fashion and be OK.

    Basically the same thing with the pointer to MyClass. MyClass isn't a base class nor does it have any virtual methods, so there is no v-table. The compiler doesn't even have to guess what function to call. And what happens in that function is just what happens always when you call printf() so that's pretty automatic. a itself could just point to some memory in the text section of the program.

    Since undefined behavior is in effect, my explanation is as reasonable as anyone else's. Whether that's what actually happens... well, I don't want to read an assembly dump of the exe. It doesn't matter anyway.
    Last edited by whiteflags; 02-26-2011 at 12:56 PM.

  8. #8
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by whiteflags View Post
    Why would it need to use an allocator? Sometimes pointers point to other memory sections than the heap. const char* is an exellent example.

    I'm thinking that b's value is just the same as the address of the literal 5 which would be in the data section (I think). Especially after this:

    *b = 5;

    You could use it in a read-only fashion and be OK.

    Basically the same thing with the pointer to MyClass. MyClass isn't a base class nor does it have any virtual methods, so there is no v-table. The compiler doesn't even have to guess what function to call. And what happens in that function is just what happens always when you call printf() so that's pretty automatic. a itself could just point to some memory in the text section of the program.

    Since undefined behavior is in effect, my explanation is as reasonable as anyone else's. Whether that's what actually happens... well, I don't want to read an assembly dump of the exe. It doesn't matter anyway.
    I didn't disassemble the executable, I only compiled the source to assembly - it was all OK, there weren't any extra instructions or anything thrown in (which is what I kind of felt was happening..).
    Code:
    gcc/g++ -S ...
    Yeah, I get the 'why' behind what was going on, I've just never seen anything work so well with undefined behavior before. On all other systems I've worked on a pointer is basically 0, and while you can't depend on that, it's typically not in your program's space, and typically not going to not blow up in your face. Very weird.

    Guess I'd just rather it crash, I'm used to that O.o. Definitely not expecting it to work fine..oh well...

  9. #9
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    I didn't disassemble the executable, I only compiled the source to assembly - it was all OK, there weren't any extra instructions or anything thrown in (which is what I kind of felt was happening..).
    I didn't talk about what you did. I'd already compiled and run the executable just to see what the result was. (By the way, I didn't exit cleanly from main, so on Windows, it does crash.)

    At first, because I was curious, I did objdump -dS main.o > main.dump

    Not enough to verify my theory. The exe dump would have been enough, but to wade through all that, just to discover what happened in this particular case, when I'm not the best at assembly anyway. I didn't see a point in running gcc again to get the assembly.

  10. #10
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by whiteflags View Post
    I didn't talk about what you did. I'd already compiled and run the executable just to see what the result was. (By the way, I didn't exit cleanly from main, so on Windows, it does crash.)

    At first, because I was curious, I did objdump -dS main.o > main.dump

    Not enough to verify my theory. The exe dump would have been enough, but to wade through all that, just to discover what happened in this particular case, when I'm not the best at assembly anyway. I didn't see a point in running gcc again to get the assembly.
    Eh, while x86 asm isn't my favorite kind (fuggggly) I don't mind looking at it...but I'm hungry, so it'll have to wait, I'll try doing an object dump, but I doubt I'll get anything (or at least not much) different than I got from just not compiling it all the way.

Popular pages Recent additions subscribe to a feed