Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Stuck up with NULL character

Stuck up with NULL character

Scheduled Pinned Locked Moved C / C++ / MFC
helpc++data-structuresquestion
13 Posts 6 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    abhijitr
    wrote on last edited by
    #1

    Hi, I have written a class as follows: class A { char str[2]; public: A (LPSTR Astr) { strcpy(str, Astr); } A& operator = (LPSTR Astr) { strcpy(str, Astr); return *this; } }; I have created a variable of the class and trying to assign it some values using following code A a1("aa"); and returning this variable from a function. This is failing with the following error message "Run_Time Check Failure#2 - Stack around the variable 'a1' was corrupted" when I do this in a MFC application. This is right since I am not leaving any space for the null character. However when I am doing the same thing in the DLL, it is running perfectly. I am not getting why it is running in DLL and failing in direct Application? Can anybody please explain?

    CPalliniC D A A 4 Replies Last reply
    0
    • A abhijitr

      Hi, I have written a class as follows: class A { char str[2]; public: A (LPSTR Astr) { strcpy(str, Astr); } A& operator = (LPSTR Astr) { strcpy(str, Astr); return *this; } }; I have created a variable of the class and trying to assign it some values using following code A a1("aa"); and returning this variable from a function. This is failing with the following error message "Run_Time Check Failure#2 - Stack around the variable 'a1' was corrupted" when I do this in a MFC application. This is right since I am not leaving any space for the null character. However when I am doing the same thing in the DLL, it is running perfectly. I am not getting why it is running in DLL and failing in direct Application? Can anybody please explain?

      CPalliniC Offline
      CPalliniC Offline
      CPallini
      wrote on last edited by
      #2

      Well, basically why bother if obviously broken code apparently works? Anyway probably you have such information because MFC (at least in debug build) puts additional code to check memory corruption. Your code is, BTW, dangerous in both the environments. :)

      If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
      This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke

      In testa che avete, signor di Ceprano?

      1 Reply Last reply
      0
      • A abhijitr

        Hi, I have written a class as follows: class A { char str[2]; public: A (LPSTR Astr) { strcpy(str, Astr); } A& operator = (LPSTR Astr) { strcpy(str, Astr); return *this; } }; I have created a variable of the class and trying to assign it some values using following code A a1("aa"); and returning this variable from a function. This is failing with the following error message "Run_Time Check Failure#2 - Stack around the variable 'a1' was corrupted" when I do this in a MFC application. This is right since I am not leaving any space for the null character. However when I am doing the same thing in the DLL, it is running perfectly. I am not getting why it is running in DLL and failing in direct Application? Can anybody please explain?

        D Offline
        D Offline
        David Crow
        wrote on last edited by
        #3

        abhijitr wrote:

        char str[2];

        This member variable does not have enough room for two characters PLUS the terminating \0 character.

        "Normal is getting dressed in clothes that you buy for work and driving through traffic in a car that you are still paying for, in order to get to the job you need to pay for the clothes and the car and the house you leave vacant all day so you can afford to live in it." - Ellen Goodman

        "To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne

        M 1 Reply Last reply
        0
        • D David Crow

          abhijitr wrote:

          char str[2];

          This member variable does not have enough room for two characters PLUS the terminating \0 character.

          "Normal is getting dressed in clothes that you buy for work and driving through traffic in a car that you are still paying for, in order to get to the job you need to pay for the clothes and the car and the house you leave vacant all day so you can afford to live in it." - Ellen Goodman

          "To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne

          M Offline
          M Offline
          Member 754960
          wrote on last edited by
          #4

          Also, the assignment operator fails to insure there will be no buffer overwrite. Simple assignments such as,

          A Astring;
          Astring = "too long";

          will cause errors. Changing the size of the buffer won't be enough. The arguments to the assignment operator should be constant; unless you intend to allow it to change its argument?!?

          A& operator = (LPCSTR Astr)
          {
          // reset the buffer
          ::memset(str, 0, sizeof(str));

          if (!Astr)
          	return \*this;
          
          int len = ::strlen(Astr);
          if (len <= sizeof(str)) {		// too short or just right
          	::strcpy(str, Astr);
          } else if (sizeof(str) < len) {	// too long
          	// Q: how to handle the terminal nul???
          	::strncpy(str, Astr, sizeof(str) - 1 );	// truncate
          	str\[1\] = '\\0';							// terminate
          }	
          	
          return \*this;
          

          }

          Should probably check for the degenerate case of an empty string as well.

          D J 2 Replies Last reply
          0
          • M Member 754960

            Also, the assignment operator fails to insure there will be no buffer overwrite. Simple assignments such as,

            A Astring;
            Astring = "too long";

            will cause errors. Changing the size of the buffer won't be enough. The arguments to the assignment operator should be constant; unless you intend to allow it to change its argument?!?

            A& operator = (LPCSTR Astr)
            {
            // reset the buffer
            ::memset(str, 0, sizeof(str));

            if (!Astr)
            	return \*this;
            
            int len = ::strlen(Astr);
            if (len <= sizeof(str)) {		// too short or just right
            	::strcpy(str, Astr);
            } else if (sizeof(str) < len) {	// too long
            	// Q: how to handle the terminal nul???
            	::strncpy(str, Astr, sizeof(str) - 1 );	// truncate
            	str\[1\] = '\\0';							// terminate
            }	
            	
            return \*this;
            

            }

            Should probably check for the degenerate case of an empty string as well.

            D Offline
            D Offline
            David Crow
            wrote on last edited by
            #5

            This should be between you and the OP.

            "Normal is getting dressed in clothes that you buy for work and driving through traffic in a car that you are still paying for, in order to get to the job you need to pay for the clothes and the car and the house you leave vacant all day so you can afford to live in it." - Ellen Goodman

            "To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne

            M 1 Reply Last reply
            0
            • D David Crow

              This should be between you and the OP.

              "Normal is getting dressed in clothes that you buy for work and driving through traffic in a car that you are still paying for, in order to get to the job you need to pay for the clothes and the car and the house you leave vacant all day so you can afford to live in it." - Ellen Goodman

              "To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne

              M Offline
              M Offline
              Member 754960
              wrote on last edited by
              #6

              Why? I don't understand.

              1 Reply Last reply
              0
              • M Member 754960

                Also, the assignment operator fails to insure there will be no buffer overwrite. Simple assignments such as,

                A Astring;
                Astring = "too long";

                will cause errors. Changing the size of the buffer won't be enough. The arguments to the assignment operator should be constant; unless you intend to allow it to change its argument?!?

                A& operator = (LPCSTR Astr)
                {
                // reset the buffer
                ::memset(str, 0, sizeof(str));

                if (!Astr)
                	return \*this;
                
                int len = ::strlen(Astr);
                if (len <= sizeof(str)) {		// too short or just right
                	::strcpy(str, Astr);
                } else if (sizeof(str) < len) {	// too long
                	// Q: how to handle the terminal nul???
                	::strncpy(str, Astr, sizeof(str) - 1 );	// truncate
                	str\[1\] = '\\0';							// terminate
                }	
                	
                return \*this;
                

                }

                Should probably check for the degenerate case of an empty string as well.

                J Offline
                J Offline
                James R Twine
                wrote on last edited by
                #7

                Your code example may confuse the OP... Your second if() test checks the length of the passed string against the length of the str buffer, instead of "length of the str buffer - 1", so the strcpy(...) executed if the if() passes will overwrite one past the end of the str buffer when it writes a terminating NUL character.    The final else if() test copies the source string correctly, but the line after that places the terminating NUL is using a hardcoded index of 1, so if str is longer than 2 characters, you will copy a truncated version of the source string and then truncate it further to one character.    Use of sizeof() to determine the character length of the buffer only works for (1) arrays that are part of the object, or automatically/locally allocated as arrays (i.e. if str is actually a pointer to an array and not a real array, it will not work as expected); and (2) only in ANSI builds - for UNICODE, the calculations will be off.    The copying of the source string can be further simplified to:

                dwStrBufferLen = /* character length of the str buffer */
                    ::strncpy( str, Astr, dwStrBufferLen );
                    str[ dwStrBufferLen - 1 ] = '\0';

                This will work regardless of the length of the target string, truncating it if necessary, and will ensure that a terminating NUL is always there.    Since ::strncpy(...) will not go past the length specified, it is one less place to be concerned with doing a correct off-by-one offset.  If it runs out of space before the end of the source string, the following line will write the terminating NUL.   Peace!

                -=- James
                Please rate this message - let me know if I helped or not! * * * If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong!
                Remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road!
                See DeleteFXPFiles

                M 1 Reply Last reply
                0
                • J James R Twine

                  Your code example may confuse the OP... Your second if() test checks the length of the passed string against the length of the str buffer, instead of "length of the str buffer - 1", so the strcpy(...) executed if the if() passes will overwrite one past the end of the str buffer when it writes a terminating NUL character.    The final else if() test copies the source string correctly, but the line after that places the terminating NUL is using a hardcoded index of 1, so if str is longer than 2 characters, you will copy a truncated version of the source string and then truncate it further to one character.    Use of sizeof() to determine the character length of the buffer only works for (1) arrays that are part of the object, or automatically/locally allocated as arrays (i.e. if str is actually a pointer to an array and not a real array, it will not work as expected); and (2) only in ANSI builds - for UNICODE, the calculations will be off.    The copying of the source string can be further simplified to:

                  dwStrBufferLen = /* character length of the str buffer */
                      ::strncpy( str, Astr, dwStrBufferLen );
                      str[ dwStrBufferLen - 1 ] = '\0';

                  This will work regardless of the length of the target string, truncating it if necessary, and will ensure that a terminating NUL is always there.    Since ::strncpy(...) will not go past the length specified, it is one less place to be concerned with doing a correct off-by-one offset.  If it runs out of space before the end of the source string, the following line will write the terminating NUL.   Peace!

                  -=- James
                  Please rate this message - let me know if I helped or not! * * * If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong!
                  Remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road!
                  See DeleteFXPFiles

                  M Offline
                  M Offline
                  Member 754960
                  wrote on last edited by
                  #8

                  Good catch! Yes, I missed a few things here. Sorry.

                  1 Reply Last reply
                  0
                  • A abhijitr

                    Hi, I have written a class as follows: class A { char str[2]; public: A (LPSTR Astr) { strcpy(str, Astr); } A& operator = (LPSTR Astr) { strcpy(str, Astr); return *this; } }; I have created a variable of the class and trying to assign it some values using following code A a1("aa"); and returning this variable from a function. This is failing with the following error message "Run_Time Check Failure#2 - Stack around the variable 'a1' was corrupted" when I do this in a MFC application. This is right since I am not leaving any space for the null character. However when I am doing the same thing in the DLL, it is running perfectly. I am not getting why it is running in DLL and failing in direct Application? Can anybody please explain?

                    A Offline
                    A Offline
                    Ali Rafiee
                    wrote on last edited by
                    #9

                    Maybe because you are running the application in debug mode, and the dll in release mode!? Either way you are corrupting memory.

                    AliR. Visual C++ MVP

                    1 Reply Last reply
                    0
                    • A abhijitr

                      Hi, I have written a class as follows: class A { char str[2]; public: A (LPSTR Astr) { strcpy(str, Astr); } A& operator = (LPSTR Astr) { strcpy(str, Astr); return *this; } }; I have created a variable of the class and trying to assign it some values using following code A a1("aa"); and returning this variable from a function. This is failing with the following error message "Run_Time Check Failure#2 - Stack around the variable 'a1' was corrupted" when I do this in a MFC application. This is right since I am not leaving any space for the null character. However when I am doing the same thing in the DLL, it is running perfectly. I am not getting why it is running in DLL and failing in direct Application? Can anybody please explain?

                      A Offline
                      A Offline
                      abhijitr
                      wrote on last edited by
                      #10

                      When I add a virtual destructor to this class it is not giving any error. It runs smoothly. However if I add simple destructor it fails.

                      A 1 Reply Last reply
                      0
                      • A abhijitr

                        When I add a virtual destructor to this class it is not giving any error. It runs smoothly. However if I add simple destructor it fails.

                        A Offline
                        A Offline
                        abhijitr
                        wrote on last edited by
                        #11

                        Hi Guys, I have finally solved the problem. If you check the size of class A it comes to be 8 (with virtual destructor) which we were expecting it to be 06 as we have used 2 bytes for ‘stre’ and 4 bytes for virtual pointer (as we have declared virtual destructor in class A). On investigation I found that size is 8 due to word alignment of structure and union members which is used to increase the performance. Due to this we are getting room for extra two characters which accommodates our null character and saves us from crashing. Thanks for your cooperation.

                        A 1 Reply Last reply
                        0
                        • A abhijitr

                          Hi Guys, I have finally solved the problem. If you check the size of class A it comes to be 8 (with virtual destructor) which we were expecting it to be 06 as we have used 2 bytes for ‘stre’ and 4 bytes for virtual pointer (as we have declared virtual destructor in class A). On investigation I found that size is 8 due to word alignment of structure and union members which is used to increase the performance. Due to this we are getting room for extra two characters which accommodates our null character and saves us from crashing. Thanks for your cooperation.

                          A Offline
                          A Offline
                          Ali Rafiee
                          wrote on last edited by
                          #12

                          I don't understand why you are not increasing the size of the buffer to 3 so that you can have 2 chars and a null, and use strncpy instead of strcpy. Why are you insisting on overwriting past your buffer?

                          AliR. Visual C++ MVP

                          A 1 Reply Last reply
                          0
                          • A Ali Rafiee

                            I don't understand why you are not increasing the size of the buffer to 3 so that you can have 2 chars and a null, and use strncpy instead of strcpy. Why are you insisting on overwriting past your buffer?

                            AliR. Visual C++ MVP

                            A Offline
                            A Offline
                            abhijitr
                            wrote on last edited by
                            #13

                            I have already implemented this class in my application and changing the string length will require me to make changes to various places which is very error prone at this stage.

                            1 Reply Last reply
                            0
                            Reply
                            • Reply as topic
                            Log in to reply
                            • Oldest to Newest
                            • Newest to Oldest
                            • Most Votes


                            • Login

                            • Don't have an account? Register

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • World
                            • Users
                            • Groups