1

My software has crashed and generated a core file. After investigating the core file, crash has occurred when free() call has been made. Noticed that the address that was passed to free was invalid.

 #1  0x000055ea2d52f630 in __free [__be___free] (ptr=0x7f8bd51a63ef, saved_caller_pc=0x55ea29cceb76 <abc+998>, attr=0x0)

The address 0x7f8bd51a63ef is invalid.

Given that we are running the program on a x86_64 ISA the word length would be 8 bits and the memory address of the word would either end with 0 or 8. Since in our case, it is ending with f, it made me to suspect it to be an invalid address. I confirmed this by dumping the memory around the memory location 0x7f8bd51a63ef (using the command x) and inspected the header data of the memory block corresponding to the address 0x7f8bd51a63ef - they appeared to be shifted by 1 byte (the shift was evident from the magic number in the header). So I dumped the data the memory around the memory location 0x7f8bd51a63f0 (which is 1 bytes higher than the previous memory address), now all the header data was displayed properly.

Additional Info: And from the memory header data, I could see that it was not an already free'd memory block

My code looks like -

100 static void
101 func (<struct type1> *arg1, <struct type2> **arg2)
102 {
103   <struct type2> *var;
104   var = *arg2;
...
...
...
...
...
125    my_free(var->abc.xyz);
...
...
130
     }  

Structure type2 would look like -

struct type3 {
  ...
  void * xyz; ---> Pointer to a timer related object
  ...
}

struct type2 {
  ...
  type3 abc;
  ...
}

I inspected the code to see if anywhere in the code, we would typecast var->abc.xyz to char or uchar and decrement it. But there is no statement in the code which is doing it. There is very few access to var->abc.xyz in code -

  1. initializing - timer object will be malloc'ed and assigned to var->abc.xyz
  2. destroying - free'ing var->abc.xyz
  3. timer actions - since var->abc.xyz is a timer object, we just start, stop and check whether it is running or not.

Only other thing I could suspect is a memory corruption by the previous memory block owner of type2 structure instance using the dangling pointer.

Previous memory block owner means - a thread, "Thread A", which had previously got the memory block, "Block M", when it called malloc and later free'd. However, "Thread A" still has a pointer holding the memory address for the memory block, "Block M". Now when thread "Thread B" makes a request through malloc, it will be allocated memory block, "Block M". Since "Thread A" still has access to "Block M", it can illegally write on "Block M"

So type2 structure instance var could be manipulated to corrupt the data at var->abc.xyz by some other thread.

  1. Is there a way to confirm this?
  2. What other possibility could be there?

Please note: I have also checked for possibility of memory overrun by previous memory block (previous memory block is different than previous owner of the memory block). From the memory block assigned to var, I have traced down the previous memory block and allocator of that block and checked for possibility of memory overrun through code inspection - there is no issue here as well since the previous memory block is accessed through only snprintf and the size passed to snprint is properly the limiting the access with its allocated memory.

3
  • 5
    Run your code through valgrind. If you're mismanaging memory it will tell you where. Commented Jul 28, 2022 at 17:16
  • The source of memory corruption that can be found with the help of Valgrind is to rerun the program and crash it again, right? If so, the crash which I am solving happened only once and not been able to reproduce so far. Valgrind can't be used to analyze the generated core file? Commented Jul 29, 2022 at 7:34
  • Valgrind can find problems even if your program doesn't crash. It detects out-of-bound memory access, reading of uninitialized variables, and double-frees as they happen, among other things. It also keeps track of allocated and freed memory and tells you if you have any leaks when your program exits. Commented Jul 29, 2022 at 12:00

1 Answer 1

3

What other possibility could be there?

You are assuming that only type2 is involved in the corruption, but often that is not the case.

Suppose you have the following:

  UnrelatedType *t = malloc(sizeof(*t));
  t->x = ...;
  free(t);    // After this, another thread may call malloc(sizeof(type2))
              // and get the same memory.
  t->x -= 1;  // write-after-free may corrupt var->abc.xyz in another thread.

There is no practical way to find such bugs by inspection -- you need to use Address Sanitizer (-fsanitize=memory), valgrind, or similar tools.

Sign up to request clarification or add additional context in comments.

7 Comments

Yes, that is what even I am suspecting. When I said previous owner of the memory block allocated to var. In this case, t would be the previous owner. Thanks, let me explore valgrind. Could you please help me understand a bit more about Address Sanitizer (-fsanitize=memory). How does this work? All I could sense is that it is a compiler flag.
@DarshanL I added a link to Address Sanitizer documentation. It's a compiler flag and a runtime library. Once you build your binary with -fsanitize=address flag, run it normally and the tool will detect "use after free" and lots of other bugs.
Should I use -fsanitize=address or -fsanitize=memory to identify "use after free"? And what is the difference between the two?
Trying -fsanitize=address resulted in this error - gcc -fsanitize=address address_sanitizer.c /bin/ld: cannot find /usr/lib64/libasan.so.5.0.0 collect2: error: ld returned 1 exit status
@DarshanL You are looking for -fsanitize=address. The -fsanitize=memory is a different project (Memory sanitizer) and catches different kinds of bugs. It's also not implemented in GCC. Re: missing libasan -- you need to install a package which contains it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.