"The same heap" isn't a coherent concept here. Your malloc-implementing memory allocator has some global state, and that state has some pointers to some addresses it got from mmap and some metadata about how long those spans of memory are, which parts are unused, and how long the values it has returned from malloc previously are. If you managed to use two of these, they would each contain data referring to different non-overlapping sets of memory mappings. If you accidentally used a pointer from one with the other, you would go instantly to C UB land:
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.