7
7
using System . IO ;
8
8
using System . Linq ;
9
9
using System . Text . RegularExpressions ;
10
+ using BenchmarkDotNet . Portability ;
10
11
11
12
namespace BenchmarkDotNet . Disassemblers
12
13
{
13
14
// This Disassembler uses ClrMd v2x. Please keep it in sync with ClrMdV1Disassembler (if possible).
14
15
internal abstract class ClrMdV2Disassembler
15
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 ) ;
21
+
16
22
internal DisassemblyResult AttachAndDisassemble ( Settings settings )
17
23
{
18
24
using ( var dataTarget = DataTarget . AttachToProcess (
@@ -270,7 +276,7 @@ protected void TryTranslateAddressToName(ulong address, bool isAddressPrecodeMD,
270
276
271
277
if ( method is null )
272
278
{
273
- if ( isAddressPrecodeMD || this is not Arm64Disassembler )
279
+ if ( isAddressPrecodeMD || ! IsVulnerableToAvInDac )
274
280
{
275
281
var methodDescriptor = runtime . GetMethodByHandle ( address ) ;
276
282
if ( ! ( methodDescriptor is null ) )
@@ -287,7 +293,7 @@ protected void TryTranslateAddressToName(ulong address, bool isAddressPrecodeMD,
287
293
}
288
294
}
289
295
290
- if ( this is not Arm64Disassembler )
296
+ if ( ! IsVulnerableToAvInDac )
291
297
{
292
298
var methodTableName = runtime . DacLibrary . SOSDacInterface . GetMethodTableName ( address ) ;
293
299
if ( ! string . IsNullOrEmpty ( methodTableName ) )
@@ -311,6 +317,22 @@ protected void TryTranslateAddressToName(ulong address, bool isAddressPrecodeMD,
311
317
state . AddressToNameMapping . Add ( address , methodName ) ;
312
318
}
313
319
320
+ protected void FlushCachedDataIfNeeded ( IDataReader dataTargetDataReader , ulong address , byte [ ] buffer )
321
+ {
322
+ if ( ! RuntimeInformation . IsWindows ( ) )
323
+ {
324
+ if ( dataTargetDataReader . Read ( address , buffer ) <= 0 )
325
+ {
326
+ // We don't suspend the benchmark process for the time of disassembling,
327
+ // as it would require sudo privileges.
328
+ // Because of that, the Tiered JIT thread might still re-compile some methods
329
+ // in the meantime when the host process it trying to disassemble the code.
330
+ // In such case, Tiered JIT thread might create stubs which requires flushing of the cached data.
331
+ dataTargetDataReader . FlushCachedData ( ) ;
332
+ }
333
+ }
334
+ }
335
+
314
336
// GetMethodByInstructionPointer sometimes returns wrong methods.
315
337
// In case given address does not belong to the methods range, null is returned.
316
338
private static ClrMethod WorkaroundGetMethodByInstructionPointerBug ( ClrRuntime runtime , ClrMethod method , ulong newAddress )
0 commit comments