2

The GNU libc manual page for mcheck says that the MCHECK_FREE status means "The block was already freed." That would imply to me that the block was freed (at least) once. This answer seems to imply the same in the code example. However, the Linux manpage says quite explicitly that MCHECK_FREE means "A block of memory was freed twice." I modified the code example from the above answer to make it slightly more descriptive:

#include <stdio.h>
#include <stdlib.h>
#include <mcheck.h>

void print_status(enum mcheck_status status)
{
    switch(status)
    {
        case MCHECK_DISABLED:
        printf("MCHECK_DISABLED\n");
        break;

        case MCHECK_OK:
        printf("MCHECK_OK\n");
        break;

        case MCHECK_HEAD:
        printf("MCHECK_HEAD\n");
        break;

        case MCHECK_TAIL:
        printf("MCHECK_TAIL\n");
        break;

        case MCHECK_FREE:
        printf("MCHECK_FREE\n");
        break;
    }
}

void no_op(enum mcheck_status status) {}

int main()
{
    mcheck(&no_op);

    void* f = malloc(4);

    print_status(mprobe(f));

    free(f);

    print_status(mprobe(f));

    return 0;
}

When I run this code I get this output:

MCHECK_OK
MCHECK_HEAD

This means I'm clearly getting MCHECK_HEAD as a response when checking a freed block. Is this behaviour reliable? Is it reasonable to expect that the header of a block will always be clobbered when it is freed? Are there different implementations of mcheck/mprobe that will return MCHECK_FREE instead?

Charlim
  • 521
  • 4
  • 12
  • 1
    gcc --version -> gcc (Ubuntu 10.2.0-13ubuntu1) 10.2.0, ldd --version -> ldd (Ubuntu GLIBC 2.32-0ubuntu3) 2.32 – Charlim Feb 07 '21 at 11:07
  • 1
    Hm, `gcc -fsanitize=address` makes it print `MCHECK_OK` twice. [The code looks simple enough](https://github.com/lattera/glibc/blob/master/malloc/mcheck.c#L93). I would consider writing to some glibc mailing list or one of developers. I believe on `free()` glibc writes something to the memory, overwriting what `freehook` has done. Ex. see [peturb_byte in malloc.c](https://github.com/lattera/glibc/blob/master/malloc/malloc.c#L1876). – KamilCuk Feb 07 '21 at 11:18
  • thanks, I'll try that – Charlim Feb 07 '21 at 18:59

1 Answers1

0

I emailed a libc developer mailing list. I split my problem into 2 questions, each of which were responded to:

  1. Which manual (GNU or Linux) is correct about MCHECK_FREE?

They are both correct, but written from slightly different perspectives.

If the block was previously free'd then you should return MCHECK_FREE.

However, if you can't detect that it was previously free'd because of corruption then you might only be able to return MCHECK_HEAD as the default results if the corruption has changed all co-located metadata about the state information.

  1. Is it reasonable to generally expect that MCHECK_HEAD will be returned [when calling mprobe on a freed pointer]?

Yes.

Charlim
  • 521
  • 4
  • 12