Repository: pwndbg/pwndbg

Issue:
`MALLOC_ALIGNMENT` might be wrong for powerpc
`MALLOC_ALIGNMENT`'s definition:
https://elixir.bootlin.com/glibc/glibc-2.37/source/sysdeps/generic/malloc-alignment.h#L27

How we implement it:
https://github.com/pwndbg/pwndbg/blob/59e759e0363cd474e662f28503f8de726baf7d20/pwndbg/heap/ptmalloc.py#L966-L974

We assume if the architecture isn't i386 and with GLIBC version >= 2.26, then `MALLOC_ALIGNMENT == 2 * SIZE_SZ`, which means we think `2 * SIZE_SZ < __alignof__ (long double)` is always `false`.

But this is not always correct for every architecture, for example, if our architecture is `powerpc:common`:
```python
In [1]: pwndbg.gdblib.typeinfo.lookup_types("long double").alignof
Out[1]: 16

In [2]: pwndbg.gdblib.arch.ptrsize * 2 < pwndbg.gdblib.typeinfo.lookup_types("long double").alignof
Out[2]: True
```

`MALLOC_ALIGNMENT` should be `16`(`__alignof__ (long double)`) instead of `8`(`2 * SIZE_SZ`) in this case.



Discussion:

Resolving patch:
diff --git a/pwndbg/heap/ptmalloc.py b/pwndbg/heap/ptmalloc.py
--- a/pwndbg/heap/ptmalloc.py
+++ b/pwndbg/heap/ptmalloc.py
@@ -965,12 +965,21 @@ def malloc_par(self):
     @pwndbg.lib.memoize.reset_on_objfile
     def malloc_alignment(self):
         """Corresponds to MALLOC_ALIGNMENT in glibc malloc.c"""
-        # i386 will override it to 16 when GLIBC version >= 2.26
-        # See https://elixir.bootlin.com/glibc/glibc-2.26/source/sysdeps/i386/malloc-alignment.h#L22
+        if pwndbg.gdblib.arch.current == "i386" and pwndbg.glibc.get_version() >= (2, 26):
+            # i386 will override it to 16 when GLIBC version >= 2.26
+            # See https://elixir.bootlin.com/glibc/glibc-2.26/source/sysdeps/i386/malloc-alignment.h#L22
+            return 16
+        # See https://elixir.bootlin.com/glibc/glibc-2.37/source/sysdeps/generic/malloc-alignment.h#L27
+        if hasattr(gdb.Type, "alignof"):
+            long_double_alignment = pwndbg.gdblib.typeinfo.lookup_types("long double").alignof
+        else:
+            # alignof doesn't available in GDB < 8.2 (https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob_plain;f=gdb/NEWS;hb=gdb-8.2-release)
+            # Hardcoded return correct MALLOC_ALIGNMENT for powerpc
+            # TODO: This will be wrong if there's another architecture similar to powerpc
+            # TODO: We can remove this when we drop supports for GDB < 8.2
+            return 16 if pwndbg.gdblib.arch.current == "powerpc" else 2 * self.size_sz
         return (
-            16
-            if pwndbg.gdblib.arch.current == "i386" and pwndbg.glibc.get_version() >= (2, 26)
-            else pwndbg.gdblib.arch.ptrsize * 2
+            long_double_alignment if 2 * self.size_sz < long_double_alignment else 2 * self.size_sz
         )
 
     @property
diff --git a/pwndbg/heap/structs.py b/pwndbg/heap/structs.py
--- a/pwndbg/heap/structs.py
+++ b/pwndbg/heap/structs.py
@@ -22,15 +22,21 @@ def fastbin_index(size: int) -> int:
         return (size >> 3) - 2
 
 
+# TODO: Move these heap constants and macros to elsewhere, because pwndbg/heap/ptmalloc.py also uses them, we are duplicating them here.
 SIZE_SZ = pwndbg.gdblib.arch.ptrsize
 MINSIZE = pwndbg.gdblib.arch.ptrsize * 4
-# i386 will override it to 16.
-# See https://elixir.bootlin.com/glibc/glibc-2.26/source/sysdeps/i386/malloc-alignment.h#L22
-MALLOC_ALIGN = (
-    16
-    if pwndbg.gdblib.arch.current == "i386" and pwndbg.glibc.get_version() >= (2, 26)
-    else pwndbg.gdblib.arch.ptrsize * 2
-)
+if pwndbg.gdblib.arch.current == "i386" and pwndbg.glibc.get_version() >= (2, 26):
+    # i386 will override it to 16 when GLIBC version >= 2.26
+    # See https://elixir.bootlin.com/glibc/glibc-2.26/source/sysdeps/i386/malloc-alignment.h#L22
+    MALLOC_ALIGN = 16
+elif hasattr(gdb.Type, "alignof"):
+    # See https://elixir.bootlin.com/glibc/glibc-2.37/source/sysdeps/generic/malloc-alignment.h#L27
+    long_double_alignment = pwndbg.gdblib.typeinfo.lookup_types("long double").alignof
+    MALLOC_ALIGN = long_double_alignment if 2 * SIZE_SZ < long_double_alignment else 2 * SIZE_SZ
+else:
+    # alignof doesn't available in GDB < 8.2 (https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob_plain;f=gdb/NEWS;hb=gdb-8.2-release)
+    # Hardcoded the MALLOC_ALIGN to 16 for powerpc, and 2 * SIZE_SZ for other archs
+    MALLOC_ALIGN = 16 if pwndbg.gdblib.arch.current == "powerpc" else 2 * SIZE_SZ
 MALLOC_ALIGN_MASK = MALLOC_ALIGN - 1
 MAX_FAST_SIZE = 80 * SIZE_SZ // 4
 NBINS = 128


Test patch: