C++ and Valgrind: Can't understand "Invalid read" error
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
C++ and Valgrind: Can't understand "Invalid read" error
Hi everybody!
I have just started using Valgrind,which really is great. Most of the reported errors look kinda weird,though...
I can't really understand what's going on here, for example:
Quote:
==00:00:02:52.033 7754== Invalid read of size 4
==00:00:02:52.033 7754== at 0x80B0987: MyCls::MyPrintf(long, char*, ...) (MyCls.cpp:270)
...
==00:00:02:52.033 7754== Address 0x47a5ee8 is 0 bytes after a block of size 296 alloc'd
...
==00:00:02:52.033 7754== by 0x809A6C1: ClsMain::taskRun(int, char**) (ClsMain.cpp:177)
==00:00:02:52.033 7754== by 0x816CFE8: main (main-C.cpp:2060)
==7754== ---- Attach to debugger ? --- [Return/N/n/Y/y/C/c] ---- Y
==00:00:02:57.410 7754== starting debugger with cmd: /usr/bin/gdb -nw /proc/7765/fd/1014 7765
GNU gdb Red Hat Linux (6.5-25.el5rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
Attaching to program: /proc/7765/fd/1014, process 7765
MyCls::MyPrintf (this=0x47a5dc0, iPrm=3,
sMsg=0x6974320 "blablabla\n"...) at MyCls.cpp:270
Basically,Valgrind reported the "Invalid Read" error at line 270 of file MyCls.cpp, which is simply a cout of the m_FilePtr variable, which is a member variable of the MyCls class. It's a FILE* variable i use to write repeatedly on a text file.
The address reported (0x47a5ee8) is 296 bytes after the "this" pointer (0x47a5dc0),as Valgrind correctly tells me,but i honestly don't understand that.
And,of course,i need to read that variable,not only for the cout (indeed,the error is reported at every reading attempt).
Besides, the application doesn't crash,but still i would like to understand if i really have to worry about this "error".
Can you please help me?
Click here to see the post LQ members have rated as the most helpful post in this thread.
Is it possible the object size exceeds the memory allocation that contains the object?
Can you disassemble a few asm instructions around 0x80B0987 (or disassemble MyCls::MyPrintf up through 0x80B0987 and post a few instructions around 0x80B0987).
If Valgrind is just wrong, that disassembly might confirm that it is wrong and also give some clue what is confusing it.
Valgrind actually reports the same kind of error i posted not only for line 270,but also 251 and 274: the common operation done in these lines is the reading of m_FilePtr.
I'm glad I asked that. So forget about what happens where that object is accessed. The problem is where the pointer to that object is created, probably in a cast from the wrong type.
Remember you quoted:
Quote:
Address 0x47a5ee8 is 0 bytes after a block of size 296 alloc'd
So you allocated a 296 byte object and then used it as a 304 byte object.
Hopefully, the part you didn't quote that appears right after the above in the Valgrind output tells you more about the call stack at the point the object was allocated.
You should find that allocation in your code. What kind of object does it think it's allocating? Then how does it come to believe that is a pointer to MyCls.
Another possibility for a bug with these symptoms:
Maybe you had a pointer to an actual object of type MyCls. Then you deleted that object. Then you allocated an unrelated 296 byte object that happened to take the same memory location. Then the bug was in continuing to use the pointer to the MyCls object that had been deleted.
You're right,the part i didn't quote leads to the declaration of a MyCls object.
Quote:
obj_tskTestQ = new MyCls("/INMsgQ");
where the only constructor parameter is the name of a posix message queue i'm using to store message received by rpc protocol.The m_FilePtr is a pointer to the file in which i'm logging every message.
I checked about your last guess (when you say "Maybe you had a pointer to an actual object of type MyCls. Then you deleted that object."): that's not the case.I don't delete the object elsewhere in the code.
Looking more carefully at the Valgrind report, i did notice that the same kind of problem (Invalid read of size 4) occurs also when the MyCls constructor is called (the line above). I also noticed that an Invalid write of the same size is reported as well.
These errors occurs only when the m_FilePtr member variable is accessed , so the problem must be in that variable.
Now...sorry for the stupid question: how is it possible that i'm allocating 296 bytes but the sizeof operator reports 304? What should i check to understand what's going on?
Thanks for the help: i'm trying to figure out what's going on in a program written by somebody else,and i still need to learn some more :-)
These errors occurs only when the m_FilePtr member variable is accessed , so the problem must be in that variable.
No. That is just a side effect of the confusion about the size of the object.
Quote:
Now...sorry for the stupid question: how is it possible that i'm allocating 296 bytes but the sizeof operator reports 304?
That is not a stupid question. That seems to be the heart of the problem.
I don't know why that is happening. Some possibilities are:
Stale .o files: You changed some source code but only recompiled some of the .o files that depend on that source code.
Inconsistent definitions or compile options: You compiled multiple .cpp files that include the same definition of MyCls, but had some other definitions or compile options inconsistent between them causing MyCls to be different sizes.
Ok,i think i found the problem! And,obviously,thanks to you!
Basically,in the MyCls header file,there are 2 member variables that are declared ONLY if the macro ILOG is defined (i guess the original author decided to do this in order to provide a toggle the logging functionality).
Quote:
#ifdef ILOG
FILE* m_FilePtr;
int m_iFileDescriptor;
#endif
The macro ILOG,though is #defined only in the MyCls cpp file.
I added the line of code:
Quote:
obj_tskTestQ = new MyCls("/INMsgQ"); cout<<"Class size:"<<sizeof(MyCls)<<" - Object size:"<<sizeof(*obj_tskTestQ)<<endl;//Added this
That cout reported me a size of 296 bytes both for the class and object.
Instead,as i already wrote,the cout i had placed in the MyCls::MyPrintf function reported a 304 size on every logging.
Inserting #define ILOG at the beginning of the MyCls header file has removed the error report.
I still have 2 doubts:
1)I wonder how this didn't lead to crashes...basically i think i was writing/reading from memory zones in which i couldn't have done it
2)Since the program is compiled using a custom makefile in which i could define the ILOG macro simply using the -D flag of gcc,is it better to use this option or stick to the #define at the top of MyCls header file?
I do thank you for your help... I really don't think i could have figure it out by myself :-)
I'm glad you posted that. Too many people ask a question or even a series of followup questions and then stop posting after some good suggestion. It's frustrating to wonder whether they gave up or whether they reached the solution but didn't bother to share. Also the solution may help someone who finds the thread later searching a similar problem.
Quote:
1)I wonder how this didn't lead to crashes...basically i think i was writing/reading from memory zones in which i couldn't have done it
Memory is allocated from the Linux kernel to your process's malloc system as large contiguous groups of 4096 byte pages. Malloc then sub allocates that into the chunks your program requests.
Accessing beyond the end of a chunk can't directly crash unless that happens to access beyond the end of the contiguous group of 4096 byte pages. That is very rare.
You were accessing just 8 bytes beyond the end of the chunk. Assuming the constructor was not inline, you were writing to those 8 bytes in the constructor.
In most cases, those 8 bytes would be data used by malloc to keep track of the size and status of the following chunk of memory. For simple memory use patterns, that following chunk would probably have been free at the time you overwrote its control info.
So the crash, if any, should occur during some subsequent attempt to allocate memory when malloc gets confused by the wrong info in those bytes describing the size and status of that free chunk.
I don't know why that subsequent crash didn't occur. But in my experience, serious bugs with no symptoms are quite common. Later someone changes some unrelated part of the program and a symptom pops up.
Quote:
Since the program is compiled using a custom makefile in which i could define the ILOG macro simply using the -D flag of gcc,is it better to use this option or stick to the #define at the top of MyCls header file?
That would depend on how ILOG is used elsewhere in the project and on the conditions under which you might change your mind about whether you want those optional members in MyCls. That may be an impossible decision to make well without understanding the intent of the original programmer.
Oh i wanted to let you know how much you helped me
And i'm really glad if somebody else will find the post useful!
The constructor isn't inline:why would it be different? (sorry,as you probably noticed i still have to learn a lot... ).
The crashes i got are also probably due to various bugs: so far i fixed 3 errors related to invalid reads/writes.... Gosh i was really mistreating memory!
The constructor isn't inline:why would it be different? (sorry,as you probably noticed i still have to learn a lot... ).
The constructor was called from code that had an incorrect size and layout for the object.
So if the constructor is inline (defined in the hpp file) the constructor will use the incorrect size and layout, so it will not overwrite memory beyond the allocated size, so it will not cause a subsequent malloc to crash. But it will construct the object incorrectly, so subsequent use of any pointers in the incorrectly constructed portion of the object ought to crash.
If the constructor is non inline (declared in the hpp but defined in the cpp), then it will construct the correct size and layout object using the incorrectly allocated space, so subsequent use of the current object should be OK, but memory beyond the object has been corrupted and should cause a later malloc to crash.
I just wanna say that valgrind gives me errors when comparing a NULL pointer etc:
struct areas *top == NULL;
while ( top == NULL)
if ( top== NULL)
not sure why valgrind says theres an error when comparing but the program doesn't crash it works very good and here is a copy: http://o0oo0.net16.net/shared/
if ( top== NULL)
not sure why valgrind says theres an error when comparing but the program doesn't crash it works very good and here is a copy: http://o0oo0.net16.net/shared/
There is no such line in the source code you linked to.
I doubt valgrind has a flaw as bad as the one you describe, so I think you misunderstood the results you saw.
I didn't say it was does valgrind give errors when you run that program?
I don't plan to try your program in Valgrind. If you had provided sufficient info in your post for me to give helpful advice, I would have attempted that. Maybe someone else will try your program in Valgrind.
Notice the thread that is now above your post. You can see it isn't very hard to give enough info in a few posts to allow an expert to give useful guidance without requiring the expert to do the work himself.
BTW, was all that above your post when I first answered you? (In other words, did you tack your post onto the bottom of a similar, but not really related, old thread?)
I really thought I made my first reply to you (Oct-03-12) in a new thread with just your original question in it. Did some moderator merge these threads for some reason?
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.