badamczewski / PowerUp

⚡ Decompilation Tools and High Productivity Utilities ⚡
GNU Affero General Public License v3.0
1.64k stars 54 forks source link

Memory layout produces confusing results #4

Closed PhDuck closed 2 years ago

PhDuck commented 2 years ago

Input:

internal struct BitArray32Sized
{
    private const int MAXBITSIZE = 32;
    private Int32 value;
    private readonly byte length;
}

internal struct BitArray64Sized
{
    private const int MAXBITSIZE = 64;
    private Int64 value;
    private readonly byte length;
}

public class Q { private readonly BitArray32Sized my; }
public class QQ { private readonly BitArray64Sized my; }

Output with issues inline.


# CompilerGen+BitArray32Sized Memory Layout. 
# (struct sizes might be wrong since they are boxed to extract layouts) 
struct CompilerGen+BitArray32Sized
{
    Fields:
      [0-3]     System.Int32 value  (4 bytes)
      [4-4]     System.Byte length  (1 bytes)
      └──────────────────────────────────────────┘
    Size:    5 # Estimated
    Padding: 0 # Estimated
}

# CompilerGen+BitArray64Sized Memory Layout. 
# (struct sizes might be wrong since they are boxed to extract layouts) 
struct CompilerGen+BitArray64Sized
{
    Fields:
      [0-7]     System.Int64 value  (8 bytes)
      [8-8]     System.Byte length  (1 bytes)
      └──────────────────────────────────────────┘
    Size:    9 # Estimated
    Padding: 0 # Estimated
}

# CompilerGen+Q Memory Layout.  
class CompilerGen+Q
{
    Metadata:
    ┌──────────────────────────────────────────┐
    │ [0-7]     Object Header       (8 bytes)  │
    │ [8-15]    Method Table Ptr    (8 bytes)  │
    └──────────────────────────────────────────┘
    Fields:
      [16-23]   CompilerGen+BitArray32Sized my(8 bytes) // This seems correct, but then there should be padding added?
    Size:    24 // This is correct, but maybe confusing if people don't know all objects have to be 24 bytes.
    Padding: 0 // Shouldn't we have three bytes of padding or don't you count the padding necessary to get to 24 bytes?
}

# CompilerGen+QQ Memory Layout.  
class CompilerGen+QQ
{
    Metadata:
    ┌──────────────────────────────────────────┐
    │ [0-7]     Object Header       (8 bytes)  │
    │ [8-15]    Method Table Ptr    (8 bytes)  │
    └──────────────────────────────────────────┘
    Fields:
      [16-23]   CompilerGen+BitArray64Sized my(8 bytes)
    Size:    32  // Math doesn't add up 8 + 8 + 8 = 24 so there has to be padding somewhere.
    Padding: 0 // Shouldn't this have some padding?
}

I guess the confusion comes from padding is necessary to get to 8 byte boundary on x64, but it seems the padding is never really shown neither in struct nor class layout.

badamczewski commented 2 years ago

It seems that I'm not counting tail padding. Also, the table grids are off for structs after the recent commit