Skip to content

Commit b91087f

Browse files
lateralusXjkotas
andauthored
Fix NativeAOT ThunksPool thunk data block size handling. (#110732)
* Fix NativeAOT ThunksPool thunk data block size handling. #88710 made a change in TunkPool.cs moving away from using a page size define to calling ThunkBlockSize to get to end of thunk data block where a common stub address get stored. This change is not equivalent on platforms where the thunk blocks are laid out in pair where a stub thunk blocks are followed by a data thunk block and all gets mapped from file. This is the schema used on Windows platforms. In that layout schema the ThunkBlockSize is 2 * page size meaning that the calculation getting to the end of the thunk data block will move to the end of next thunk stub that is RX memory and storing the common stub address at that location will trigger an AV. This works on iOS since it reports its ThunkBlockSize as one page but that is not totally correct since it uses 2 pages, just that they are allocated in the same way as FEATURE_RX_THUNKS, all thunk stubs blocks followed by all thunk data blocks. The reason why this works is because it only maps the thunk stubs from file, reporting a ThunkBlockSize that is inline with what gets map:ed from file, but then there is a special handling in PalAllocateThunksFromTemplate on iOS that virutal alloc template size * 2, mapping the first template size bytes from the file and the rest are kept as its thunk data blocks. This commit adds a new function returning the size of the thunk data block and use that when calculating the end of the data block instead of using the ThunkBlockSize since its reflects the size of each block getting mapped from file, on Windows platforms that is stub+data, 2 * page size. * Switch to ThunkDataBlockSizeMask in one place. * Include pointer size slot in data block size calculation. Co-authored-by: Jan Kotas <[email protected]>
1 parent 36fef72 commit b91087f

File tree

1 file changed

+13
-10
lines changed
  • src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime

1 file changed

+13
-10
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
//
3636

3737
using System.Diagnostics;
38+
using System.Numerics;
3839

3940
namespace System.Runtime
4041
{
@@ -44,8 +45,10 @@ internal static class Constants
4445
public static readonly int ThunkCodeSize = RuntimeImports.RhpGetThunkSize();
4546
public static readonly int NumThunksPerBlock = RuntimeImports.RhpGetNumThunksPerBlock();
4647
public static readonly int NumThunkBlocksPerMapping = RuntimeImports.RhpGetNumThunkBlocksPerMapping();
47-
public static readonly uint ThunkBlockSize = (uint)RuntimeImports.RhpGetThunkBlockSize();
48-
public static readonly nuint ThunkBlockSizeMask = ThunkBlockSize - 1;
48+
public static readonly uint ThunkCodeBlockSize = BitOperations.RoundUpToPowerOf2((uint)(ThunkCodeSize * NumThunksPerBlock));
49+
public static readonly nuint ThunkCodeBlockSizeMask = ThunkCodeBlockSize - 1;
50+
public static readonly uint ThunkDataBlockSize = BitOperations.RoundUpToPowerOf2((uint)(ThunkDataSize * NumThunksPerBlock + IntPtr.Size));
51+
public static readonly nuint ThunkDataBlockSizeMask = ThunkDataBlockSize - 1;
4952
}
5053

5154
internal class ThunksHeap
@@ -97,11 +100,11 @@ private unsafe ThunksHeap(IntPtr commonStubAddress)
97100
IntPtr thunkDataBlock = RuntimeImports.RhpGetThunkDataBlockAddress(thunkStubsBlock);
98101

99102
// Address of the first thunk data cell should be at the beginning of the thunks data block (page-aligned)
100-
Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.ThunkBlockSize) == 0);
103+
Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.ThunkDataBlockSize) == 0);
101104

102105
// Update the last pointer value in the thunks data section with the value of the common stub address
103-
*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkBlockSize - IntPtr.Size)) = commonStubAddress;
104-
Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkBlockSize - IntPtr.Size)) == commonStubAddress);
106+
*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkDataBlockSize - IntPtr.Size)) = commonStubAddress;
107+
Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkDataBlockSize - IntPtr.Size)) == commonStubAddress);
105108

106109
// Set the head and end of the linked list
107110
_nextAvailableThunkPtr = thunkDataBlock;
@@ -153,11 +156,11 @@ private unsafe bool ExpandHeap()
153156
IntPtr thunkDataBlock = RuntimeImports.RhpGetThunkDataBlockAddress(thunkStubsBlock);
154157

155158
// Address of the first thunk data cell should be at the beginning of the thunks data block (page-aligned)
156-
Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.ThunkBlockSize) == 0);
159+
Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.ThunkDataBlockSize) == 0);
157160

158161
// Update the last pointer value in the thunks data section with the value of the common stub address
159-
*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkBlockSize - IntPtr.Size)) = _commonStubAddress;
160-
Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkBlockSize - IntPtr.Size)) == _commonStubAddress);
162+
*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkDataBlockSize - IntPtr.Size)) = _commonStubAddress;
163+
Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkDataBlockSize - IntPtr.Size)) == _commonStubAddress);
161164

162165
// Link the last entry in the old list to the first entry in the new list
163166
*((IntPtr*)_lastThunkPtr) = thunkDataBlock;
@@ -210,7 +213,7 @@ public unsafe IntPtr AllocateThunk()
210213
*((IntPtr*)(nextAvailableThunkPtr + IntPtr.Size)) = IntPtr.Zero;
211214
#endif
212215

213-
int thunkIndex = (int)(((nuint)(nint)nextAvailableThunkPtr) - ((nuint)(nint)nextAvailableThunkPtr & ~Constants.ThunkBlockSizeMask));
216+
int thunkIndex = (int)(((nuint)(nint)nextAvailableThunkPtr) - ((nuint)(nint)nextAvailableThunkPtr & ~Constants.ThunkDataBlockSizeMask));
214217
Debug.Assert((thunkIndex % Constants.ThunkDataSize) == 0);
215218
thunkIndex /= Constants.ThunkDataSize;
216219

@@ -266,7 +269,7 @@ private static IntPtr TryGetThunkDataAddress(IntPtr thunkAddress)
266269
nuint thunkAddressValue = (nuint)(nint)ClearThumbBit(thunkAddress);
267270

268271
// Compute the base address of the thunk's mapping
269-
nuint currentThunksBlockAddress = thunkAddressValue & ~Constants.ThunkBlockSizeMask;
272+
nuint currentThunksBlockAddress = thunkAddressValue & ~Constants.ThunkCodeBlockSizeMask;
270273

271274
// Make sure the thunk address is valid by checking alignment
272275
if ((thunkAddressValue - currentThunksBlockAddress) % (nuint)Constants.ThunkCodeSize != 0)

0 commit comments

Comments
 (0)