Repository: pwndbg/pwndbg

Issue:
Heap commands not working properly for i386 binary
<!--
Before reporting a new issue, make sure that we do not have any duplicates already open.
If there is one it might be good to take part in the discussion there.

Please make sure you have checked that the issue persists on LATEST pwndbg version.

Below is a template for BUG REPORTS.
Don't include it if this is a FEATURE REQUEST.
-->


### Description

<!--
Briefly describe the problem you are having in a few paragraphs.
-->

The commands `heap` and `vis_heap_chunks` are not working properly for an i386 compiled binary using the latest pwndbg version, however, they are working with an older pwndbg version (2022.08.30). When compiled as x86-64, both commands work with the latest version.

### Steps to reproduce

<!--
What do we have to do to reproduce the problem?
If this is connected to particular C/asm code, 
please provide the smallest C code that reproduces the issue.
-->

```c
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char *p1 = (char*)malloc(32);
    free(p1);
	
    return 0;
}
```

`gcc -m32 -g -o main main.c` 

latest pwndbg:
```
pwndbg> set exception-verbose on
pwndbg> start
pwndbg> n
pwndbg> heap
Allocated chunk
Addr: 0x5655a000
Size: 0x00

pwndbg> vis_heap_chunks

pwndbg>
```

pwndbg #2022.08.30:

```
pwndbg> start
pwndbg> n
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x5655a008
Size: 0x191

Allocated chunk | PREV_INUSE
Addr: 0x5655a198
Size: 0x31

Top chunk | PREV_INUSE
Addr: 0x5655a1c8
Size: 0x21e39

pwndbg> vis_heap_chunks
(...)
0x5655a198      0x00000000      0x00000031      ....1...
0x5655a1a0      0x00000000      0x00000000      ........
0x5655a1a8      0x00000000      0x00000000      ........
0x5655a1b0      0x00000000      0x00000000      ........
0x5655a1b8      0x00000000      0x00000000      ........
0x5655a1c0      0x00000000      0x00000000      ........
0x5655a1c8      0x00000000      0x00021e39      ....9...         <-- Top chunk
pwndbg>
```

When `gcc -g -o main main.c`  is used (`-m32` flag omitted), both commands work on the latest pwndbg version.

### My setup

<!--
Show us your gdb/python/pwndbg/OS/IDA Pro version (depending on your case).

NOTE: We are currently supporting only Ubuntu installations.
It is known that pwndbg is not fully working e.g. on Arch Linux (the heap stuff is not working there).
If you would like to change this situation - help us improving pwndbg and supporting other distros!

This can be displayed in pwndbg through `version` command.

If it is somehow unavailable, use:
* `show version` - for gdb
* `py import sys; print(sys.version)` - for python
* pwndbg version/git commit id
-->

```
pwndbg> version
Gdb:      12.1
Python:   3.10.7 (main, Nov 24 2022, 19:45:47) [GCC 12.2.0]
Pwndbg:   1.1.1 build: a3dcfaa
Capstone: 4.0.1024
Unicorn:  2.0.1
```

```bash
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.10
Release:        22.10
Codename:       kinetic
```




Discussion:
Thanks for the bug report, do you have time to `git bisect` this down to the troublesome commit?
Here is the result of `git bisect`:
```
f71a4aa65d8a1d4c0bc82848fab2ce65c23e3f77 is the first bad commit
commit f71a4aa65d8a1d4c0bc82848fab2ce65c23e3f77
Author: CptGibbon <16000770+CptGibbon@users.noreply.github.com>
Date:   Tue Nov 8 12:00:27 2022 -0800

    Reduce heap code redundancy (#1346)

    * Add get_sbrk_heap_region() method

    * Use SIZE_BITS in Chunk.real_size()

    * Add non_contiguous property to Arena class

    * Improve Heap class

    * More accurate arena detection
    * Integrate Heap class into Chunk class

    * Don't parse bins when no arena in find_fake_fast

    * Add active_heap property to Arena class

    * Add more functionality to heap classes

    * next_chunk method for Chunk class
    * prev property & __str__ method for Heap class
    * heaps property for Arena class
    * arenas command updated to reflect changes to Arena class
    * Use deepcopy() in get_region() to avoid changing vmmap command output
    * Import fiddling to deal with unrelated bug

    * Attempt at integration with heap commands

    With debug syms looks good, still issues to iron out with heuristics

    * Remove redundant heap functions

    * Remove redundant functions from tests

    * Add system_mem property to Arena class

    * thread_arena returns main_arena if single thread

 pwndbg/commands/heap.py                     | 144 ++---
 pwndbg/constants/ptmalloc.py                |   1 +
 pwndbg/heap/ptmalloc.py                     | 795 ++++++++++++++--------------
 tests/gdb-tests/tests/heap/test_heap.py     |   6 +-
 tests/gdb-tests/tests/heap/test_try_free.py |   4 +-
 5 files changed, 468 insertions(+), 482 deletions(-)
```
Yeah I thought this might be my fault, I probably (accidentally) removed the i386 heap offset code in that PR. I'll get to fixing this tomorrow morning.

Resolving patch:
diff --git a/pwndbg/heap/ptmalloc.py b/pwndbg/heap/ptmalloc.py
--- a/pwndbg/heap/ptmalloc.py
+++ b/pwndbg/heap/ptmalloc.py
@@ -393,6 +393,9 @@ def __init__(self, addr, arena=None) -> None:
                 self._gdbValue = None
 
         self.start = self._memory_region.start
+        # i686 alignment heuristic
+        if Chunk(self.start).size == 0:
+            self.start += pwndbg.gdblib.arch.ptrsize * 2
         self.end = self._memory_region.end
         self.first_chunk = Chunk(self.start)
 


Test patch: