diff --git a/fuzzing/coverage/coverage_maps.go b/fuzzing/coverage/coverage_maps.go index 59237669..9841b975 100644 --- a/fuzzing/coverage/coverage_maps.go +++ b/fuzzing/coverage/coverage_maps.go @@ -16,6 +16,10 @@ type CoverageMaps struct { // maps represents a structure used to track every ContractCoverageMap by a given deployed address/lookup hash. maps map[common.Hash]map[common.Address]*ContractCoverageMap + // TODO comment this + // The assumption here is that geth codehash matches if and only if codehash matches + cachedGethCodeHash common.Hash + // cachedCodeAddress represents the last code address which coverage was updated for. This is used to prevent an // expensive lookup in maps. If cachedCodeHash does not match the current code address for which we are updating // coverage for, it, along with other cache variables are updated. @@ -46,6 +50,7 @@ func (cm *CoverageMaps) Reset() { cm.maps = make(map[common.Hash]map[common.Address]*ContractCoverageMap) cm.cachedCodeAddress = common.Address{} cm.cachedCodeHash = common.Hash{} + cm.cachedGethCodeHash = common.Hash{} cm.cachedMap = nil } @@ -170,7 +175,7 @@ func (cm *CoverageMaps) Update(coverageMaps *CoverageMaps) (bool, bool, error) { } // UpdateAt updates the hit count of a given program counter location within code coverage data. -func (cm *CoverageMaps) UpdateAt(codeAddress common.Address, codeLookupHash common.Hash, codeSize int, pc uint64) (bool, error) { +func (cm *CoverageMaps) UpdateAt(codeAddress common.Address, gethCodeHash common.Hash, codeLookupHash common.Hash, codeSize int, pc uint64) (bool, error) { // If the code size is zero, do nothing if codeSize == 0 { return false, nil @@ -185,7 +190,7 @@ func (cm *CoverageMaps) UpdateAt(codeAddress common.Address, codeLookupHash comm ) // Try to obtain a coverage map from our cache - if cm.cachedMap != nil && cm.cachedCodeAddress == codeAddress && cm.cachedCodeHash == codeLookupHash { + if cm.cachedMap != nil && cm.cachedCodeAddress == codeAddress && cm.cachedCodeHash == codeLookupHash && cm.cachedGethCodeHash == gethCodeHash { coverageMap = cm.cachedMap } else { // If a coverage map lookup for this code hash doesn't exist, create the mapping. @@ -207,6 +212,7 @@ func (cm *CoverageMaps) UpdateAt(codeAddress common.Address, codeLookupHash comm // Set our cached variables for faster coverage setting next time this method is called. cm.cachedMap = coverageMap cm.cachedCodeHash = codeLookupHash + cm.cachedGethCodeHash = gethCodeHash cm.cachedCodeAddress = codeAddress } diff --git a/fuzzing/coverage/coverage_tracer.go b/fuzzing/coverage/coverage_tracer.go index 2f1a47e9..5f4ac2a3 100644 --- a/fuzzing/coverage/coverage_tracer.go +++ b/fuzzing/coverage/coverage_tracer.go @@ -157,18 +157,24 @@ func (t *CoverageTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tr address := scope.Address() // We can cast OpContext to ScopeContext because that is the type passed to OnOpcode. scopeContext := scope.(*vm.ScopeContext) + gethCodeHash := scopeContext.Contract.CodeHash code := scopeContext.Contract.Code codeSize := len(code) if codeSize > 0 { // Obtain our contract coverage map lookup hash. if callFrameState.lookupHash == nil { - lookupHash := getContractCoverageMapHash(code, callFrameState.create) - callFrameState.lookupHash = &lookupHash + if callFrameState.pendingCoverageMap.cachedGethCodeHash == gethCodeHash { + lookupHash := callFrameState.pendingCoverageMap.cachedCodeHash + callFrameState.lookupHash = &lookupHash + } else { + lookupHash := getContractCoverageMapHash(code, callFrameState.create) + callFrameState.lookupHash = &lookupHash + } } // Record coverage for this location in our map. - _, coverageUpdateErr := callFrameState.pendingCoverageMap.UpdateAt(address, *callFrameState.lookupHash, codeSize, pc) + _, coverageUpdateErr := callFrameState.pendingCoverageMap.UpdateAt(address, gethCodeHash, *callFrameState.lookupHash, codeSize, pc) if coverageUpdateErr != nil { logging.GlobalLogger.Panic("Coverage tracer failed to update coverage map while tracing state", coverageUpdateErr) }