3

I havent used valgrind before but I think it should detect some memory errors.

My code:

#include <stdio.h>
unsigned int a[2];

int main()
{
    a[-1] = 21;

    printf("%d,", a[-1]);

    return 1;
}

As you can see, I am accessing a[-1] which I should not.

How am I using valgrind?

I am compiling with gcc -g -O0 codeFile.c

And executing: valgrind -s ./a.out

Result is:

==239== Memcheck, a memory error detector

==239== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.

==239== Using Valgrind-3.16.0.GIT and LibVEX; rerun with -h for copyright info

==239== Command: ./a.out

==239== 21,==239==

==239== HEAP SUMMARY:

==239== in use at exit: 0 bytes in 0 blocks

==239== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated

==239==

==239== All heap blocks were freed -- no leaks are possible

==239==

==239== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Shouldnt valgrind find these error, or am I using it wrong?

EDIT: It seems that valgrind memcheck does not do anything for global variables and as suggested in the answers/comments that it should work with indexes further from the pointer, therefore: I removed the global declaration and added it insude main, and accessed a[-10] instead of a[1]. Same behaviour.

int main()
{
    unsigned int a[2];
    a[-10] = 21;

    printf("%d,", a[-10]);

    return 1;
}

It actually throws error if I use a[-100] though. Whats the deal?

EDIT 2

Furthermore, why this has no errors

while (i <= 2)
    {
        j = a[i];       
        i++;
    }

But this does

while (i <= 2)
    {
        printf("%d,", a[i]);        
        i++;
    }
Community
  • 1
  • 1
kkica
  • 4,034
  • 1
  • 20
  • 40
  • 1
    `a[-1]` may not result in a memory error. As far as valgrind is concerned, it just so happens that your program is writing `21` to a valid memory region. – KamilCuk Dec 14 '19 at 20:20
  • I would have guessed that, but why though? – kkica Dec 14 '19 at 20:39
  • I can't seem to find any documentation about what the -s flag does. – pr0f3ss Dec 14 '19 at 20:41
  • `why though` - Why would expect the kernel to insert a memory protected area anywhere inside your program? It would make your program execution really, really slow and kernel would have to use a lot of memory to mark (and to remember about all) small regions of memory that are protected. – KamilCuk Dec 14 '19 at 20:42
  • @pr0f3ss [here it is](http://valgrind.org/docs/manual/manual-core.html#manual-core.options) – KamilCuk Dec 14 '19 at 20:42
  • 1
    @pr0f3ss -s is equivalent to --show-error-list=yes. – kkica Dec 14 '19 at 20:52

2 Answers2

4

Valgrind usually can't find memory errors where the memory being modified is at a negative offset from the current stack pointer or memory that coincides with another variable in memory.

For example, if a was on the stack, a[3] would trigger memcheck. a[-1] would not, because that, for all Valgrind knows, could easily be valid memory.

To expand on that, here's a quote from the documentation with my emphasis added:

In this example, Memcheck can't identify the address. Actually the address is on the stack, but, for some reason, this is not a valid stack address -- it is below the stack pointer and that isn't allowed.

This quote is actually partially incorrect; when it says "below the stack pointer" it really means at a positive offset from the stack pointer, or interfering with another function's stack memory.

I should also note that (from your second edit) Valgrind doesn't actually complain until the value is used in some meaningful way. Assignment is, in Valgrind's eyes, not using the value in a meaningful way. Here's another quote to back that up with my emphasis added:

It is important to understand that your program can copy around junk (uninitialised) data as much as it likes. Memcheck observes this and keeps track of the data, but does not complain. A complaint is issued only when your program attempts to make use of uninitialised data in a way that might affect your program's externally-visible behaviour.

Because a is a global variable, you'll have a hard time trying to check the memory of it. One Valgrind tool I've used before that deals with this is exp-sgcheck (experimental static and global variable check), although I've found it to be unreliable (most likely due to it being experimental).

An easier and better way to detect these would be to enable compiler warnings or use a static analyzer (my favorite is LLVM's scan-build).

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • Why cant it? What decides the few bytes? If I were to do a[-100] would it work? or a[-1000]? I mean how will it find it? – kkica Dec 14 '19 at 20:38
  • even -10 does not work, but -100 does. Check my edited post – kkica Dec 14 '19 at 20:53
  • +1 for explaining the negative offset. Can you provide with an answer for the positive offset so I can accept your answer (check Edit2 in my question) – kkica Dec 14 '19 at 21:22
  • @KristjanKica Here's another edit and another documentation quote. – S.S. Anne Dec 14 '19 at 21:34
1

You declared a as an global array, so use --tool=exp-sgcheck to check for stack and global array overruns. Keep in mind that --tool=exp-sgcheck is an experimental implementation so it doesn't show up whenever enabling -s or --show-error-list=yes, you can read more about it here.

pr0f3ss
  • 527
  • 1
  • 4
  • 17
  • I have a "valgrind: failed to start tool 'exp-sgchec' for platform 'amd64-linux': No such file or directory" when I try it. I will check if its a version or fact that I am using wsl2. +1 Thanks for the global array hint. – kkica Dec 14 '19 at 20:44
  • 1
    @KristjanKica I think you have a spelling error, add a 'k' to the end of sgcheck. – pr0f3ss Dec 14 '19 at 20:47
  • Ah, yes, thanks. It is adding `warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93` – kkica Dec 14 '19 at 20:56
  • Note that exp-sgcheck no longer exists (removed in Valgrind 3.16 May 2020) – Paul Floyd Mar 02 '23 at 14:12