@@ -14,10 +14,32 @@ namespace BenchmarkDotNet.Disassemblers
14
14
// This Disassembler uses ClrMd v2x. Please keep it in sync with ClrMdV1Disassembler (if possible).
15
15
internal abstract class ClrMdV2Disassembler
16
16
{
17
- // Translating an address to a method can cause AV and a process crash (https://github.com/dotnet/BenchmarkDotNet/issues/2070).
18
- // It was fixed in https://github.com/dotnet/runtime/pull/79846,
19
- // and most likely will be backported to 7.0.2 very soon (https://github.com/dotnet/runtime/pull/79862).
20
- protected static readonly bool IsVulnerableToAvInDac = ! RuntimeInformation . IsWindows ( ) && Environment . Version < new Version ( 7 , 0 , 2 ) ;
17
+ private static readonly ulong MinValidAddress = GetMinValidAddress ( ) ;
18
+
19
+ private static ulong GetMinValidAddress ( )
20
+ {
21
+ // https://github.com/dotnet/BenchmarkDotNet/pull/2413#issuecomment-1688100117
22
+ if ( RuntimeInformation . IsWindows ( ) )
23
+ return ushort . MaxValue + 1 ;
24
+ if ( RuntimeInformation . IsLinux ( ) )
25
+ return ( ulong ) Environment . SystemPageSize ;
26
+ if ( RuntimeInformation . IsMacOS ( ) )
27
+ return RuntimeInformation . GetCurrentPlatform ( ) switch
28
+ {
29
+ Environments . Platform . X86 or Environments . Platform . X64 => 4096 ,
30
+ Environments . Platform . Arm64 => 0x100000000 ,
31
+ _ => throw new NotSupportedException ( $ "{ RuntimeInformation . GetCurrentPlatform ( ) } is not supported")
32
+ } ;
33
+ throw new NotSupportedException ( $ "{ System . Runtime . InteropServices . RuntimeInformation . OSDescription } is not supported") ;
34
+ }
35
+
36
+ private static bool IsValidAddress ( ulong address )
37
+ // -1 (ulong.MaxValue) address is invalid, and will crash the runtime in older runtimes. https://github.com/dotnet/runtime/pull/90794
38
+ // 0 is NULL and therefore never valid.
39
+ // Addresses less than the minimum virtual address are also invalid.
40
+ => address != ulong . MaxValue
41
+ && address != 0
42
+ && address >= MinValidAddress ;
21
43
22
44
internal DisassemblyResult AttachAndDisassemble ( Settings settings )
23
45
{
@@ -245,13 +267,13 @@ protected static bool TryReadNativeCodeAddresses(ClrRuntime runtime, ClrMethod m
245
267
return false ;
246
268
}
247
269
248
- protected void TryTranslateAddressToName ( ulong address , bool isAddressPrecodeMD , State state , bool isIndirectCallOrJump , int depth , ClrMethod currentMethod )
270
+ protected void TryTranslateAddressToName ( ulong address , bool isAddressPrecodeMD , State state , int depth , ClrMethod currentMethod )
249
271
{
250
- var runtime = state . Runtime ;
251
-
252
- if ( state . AddressToNameMapping . ContainsKey ( address ) )
272
+ if ( ! IsValidAddress ( address ) || state . AddressToNameMapping . ContainsKey ( address ) )
253
273
return ;
254
274
275
+ var runtime = state . Runtime ;
276
+
255
277
var jitHelperFunctionName = runtime . GetJitHelperFunctionName ( address ) ;
256
278
if ( ! string . IsNullOrEmpty ( jitHelperFunctionName ) )
257
279
{
@@ -260,9 +282,9 @@ protected void TryTranslateAddressToName(ulong address, bool isAddressPrecodeMD,
260
282
}
261
283
262
284
var method = runtime . GetMethodByInstructionPointer ( address ) ;
263
- if ( method is null && ( address & ( ( uint ) runtime . DataTarget . DataReader . PointerSize - 1 ) ) == 0 )
285
+ if ( method is null && ( address & ( ( uint ) runtime . DataTarget . DataReader . PointerSize - 1 ) ) == 0 )
264
286
{
265
- if ( runtime . DataTarget . DataReader . ReadPointer ( address , out ulong newAddress ) && newAddress > ushort . MaxValue )
287
+ if ( runtime . DataTarget . DataReader . ReadPointer ( address , out ulong newAddress ) && IsValidAddress ( newAddress ) )
266
288
{
267
289
method = runtime . GetMethodByInstructionPointer ( newAddress ) ;
268
290
@@ -276,31 +298,24 @@ protected void TryTranslateAddressToName(ulong address, bool isAddressPrecodeMD,
276
298
277
299
if ( method is null )
278
300
{
279
- if ( isAddressPrecodeMD || ! IsVulnerableToAvInDac )
301
+ var methodDescriptor = runtime . GetMethodByHandle ( address ) ;
302
+ if ( methodDescriptor is not null )
280
303
{
281
- var methodDescriptor = runtime . GetMethodByHandle ( address ) ;
282
- if ( ! ( methodDescriptor is null ) )
304
+ if ( isAddressPrecodeMD )
283
305
{
284
- if ( isAddressPrecodeMD )
285
- {
286
- state . AddressToNameMapping . Add ( address , $ "Precode of { methodDescriptor . Signature } ") ;
287
- }
288
- else
289
- {
290
- state . AddressToNameMapping . Add ( address , $ "MD_{ methodDescriptor . Signature } ") ;
291
- }
292
- return ;
306
+ state . AddressToNameMapping . Add ( address , $ "Precode of { methodDescriptor . Signature } ") ;
293
307
}
308
+ else
309
+ {
310
+ state . AddressToNameMapping . Add ( address , $ "MD_{ methodDescriptor . Signature } ") ;
311
+ }
312
+ return ;
294
313
}
295
314
296
- if ( ! IsVulnerableToAvInDac )
315
+ var methodTableName = runtime . DacLibrary . SOSDacInterface . GetMethodTableName ( address ) ;
316
+ if ( ! string . IsNullOrEmpty ( methodTableName ) )
297
317
{
298
- var methodTableName = runtime . DacLibrary . SOSDacInterface . GetMethodTableName ( address ) ;
299
- if ( ! string . IsNullOrEmpty ( methodTableName ) )
300
- {
301
- state . AddressToNameMapping . Add ( address , $ "MT_{ methodTableName } ") ;
302
- return ;
303
- }
318
+ state . AddressToNameMapping . Add ( address , $ "MT_{ methodTableName } ") ;
304
319
}
305
320
return ;
306
321
}
0 commit comments