|
From: Vincent Penquerc'h <Vin...@ar...> - 2003-08-05 10:02:45
|
> Till now I'am only disappointed by one point about valgrind, > and that is the > lack of monitoring of local memory within function call. > Especially detects > it no under or over runs for arrays. Yes, that could be fixed by adding non addressable "padding" bytes before and after an array, I guess. Though I'm not sure if Valgrind could detect the creation of such an array from the instructions though. And it would definitely not be able to do so if there are more than one arrays that are merged together in their creation (which is just a manipulation of the stack pointer). For this kind of things, I believe there exist some patches to GCC to detect stack smashing (extra code being emitted to check for the return address to be left unchanged between a function being entered and it being left). I can't be more specific now, I've never actually had a look, just heard of it. Google may help on this one. -- Vincent Penquerc'h |
|
From: Vincent Penquerc'h <Vin...@ar...> - 2003-08-05 10:55:26
|
> a good sign, but there are other, weirder ways of entering a function, > like jumps (used by dynamically linked libraries a lot) and > things like > pushing a functions start address and doing 'ret', and other horrible > things. The best way, AFAIK, is to rely on the symbol information. You got me thinking... I could think of setting a signal handler to the routine we want to call, raising that signal, and then modifying the stack and returning. Hmmm, I don't think I want to try that :) -- Vincent Penquerc'h |
|
From: Nicholas N. <nj...@ca...> - 2003-08-05 10:29:43
|
On Tue, 5 Aug 2003, Vincent Penquerc'h wrote:
> > Till now I'am only disappointed by one point about valgrind, and that
> > is the lack of monitoring of local memory within function call.
> > Especially detects it no under or over runs for arrays.
>
> Yes, that could be fixed by adding non addressable "padding"
> bytes before and after an array, I guess. Though I'm not sure
> if Valgrind could detect the creation of such an array from
> the instructions though. And it would definitely not be able
> to do so if there are more than one arrays that are merged
> together in their creation (which is just a manipulation of
> the stack pointer).
It's extremely difficult to do anything useful just by watching the stack
pointer. GCC generates code in such a way that %esp jumps all over the
place, leaving holes in the stack that aren't used, things like that. I
think the only way you can get anything sensible about the structure of
the stack is to use debug information, without it, you just can't tell
where stack arrays/variables start and end. (Static arrays are similarly
difficult. Heap-allocated arrays are trivial by comparison.)
Similarly, you can't even tell for sure when you've entered a function
just by watching the dynamic instruction stream; a 'call' instruction is
a good sign, but there are other, weirder ways of entering a function,
like jumps (used by dynamically linked libraries a lot) and things like
pushing a functions start address and doing 'ret', and other horrible
things. The best way, AFAIK, is to rely on the symbol information.
On Tue, 5 Aug 2003, Erik Corry wrote:
> > Well, the array overruns not detected by Valgrind will never cause a seg
> > fault.
>
> Not true:
>
> void f()
> {
> char a[4];
> int *b;
> int c;
> b = &c;
> a[5] = 123;
> *b = 456;
> }
>
> valgrind will tell you that the write through b is a problem,
> but the real reason is the array overrun which valgrind cannot
> detect, but which (indirectly) causes an array overrun.
I just tried it, without problems, but that's probably due to GCC adding
random padding between 'a' and 'b'.
You're right, I should have been more precise: if you get a seg fault due
to an array overrun, Valgrind will always give you some related error
message before the seg fault happens. Any objections to that statement? :)
N
|
|
From: Erik C. <er...@ar...> - 2003-08-05 10:53:33
|
On Tue, Aug 05, 2003 at 11:29:39AM +0100, Nicholas Nethercote wrote:
> >
> > void f()
> > {
> > char a[4];
> > int *b;
> > int c;
> > b = &c;
> > a[5] = 123;
> > *b = 456;
> > }
> >
> > valgrind will tell you that the write through b is a problem,
> > but the real reason is the array overrun which valgrind cannot
> > detect, but which (indirectly) causes an array overrun.
>
> I just tried it, without problems, but that's probably due to GCC adding
> random padding between 'a' and 'b'.
I think it could be because I got the stack growth direction wrong.
This one crashes like it should.
void main()
{
int *b;
char a[4];
int c;
b = &c;
a[7] = 123; // Oops!
*b = 456; // Boom!
}
> You're right, I should have been more precise: if you get a seg fault due
> to an array overrun, Valgrind will always give you some related error
> message before the seg fault happens. Any objections to that statement? :)
No objection. Valgrind gives an error message before the seg fault.
Unfortunately the error message relates to the "Boom" and not the
"Oops" line, so it's not very useful in this sort of case. The
only answer is a version of gcc with fat pointers like the one I
linked to.
By the way, I don't think Purify or Electric Fence can catch this
one either, and the nasty thing about it is that it's often a latent
bug that waits for the right (wrong) input, so you can't catch it
except by sitting down and reasoning about the program. That applies
even to Java, where you can easily get the array bounds exception far
too late (after the program started being used for real work).
--
Erik Corry er...@ar...
|
|
From: Igmar P. <mai...@jd...> - 2003-08-05 13:57:44
|
> > void f()
> > {
> > char a[4];
> > int *b;
> > int c;
> > b = &c;
> > a[5] = 123;
> > *b = 456;
> > }
> >
> > valgrind will tell you that the write through b is a problem,
> > but the real reason is the array overrun which valgrind cannot
> > detect, but which (indirectly) causes an array overrun.
>
> I just tried it, without problems, but that's probably due to GCC adding
> random padding between 'a' and 'b'.
GCC 3.x adds far more padding and alignment than 2.95.x does. No idea what
the reason is, but I observed that when debugging with code generated by
gcc -S
> You're right, I should have been more precise: if you get a seg fault due
> to an array overrun, Valgrind will always give you some related error
> message before the seg fault happens. Any objections to that statement? :)
I've seen a number of occasions when valgrind is totally of the track, all
of them with threaded apps screwing up each other stack. Gives nice
extremely hard to track problems :)
Igmar
|