diff --git a/ReleaseNotes.tmp b/ReleaseNotes.tmp index f1750c803..3cc108b09 100644 --- a/ReleaseNotes.tmp +++ b/ReleaseNotes.tmp @@ -1,4 +1,11 @@ Version [[version]] +#329 address ArgumentOutOfRangeException (potentially related to #274) (fix for VS2015) +#335 error on unrecognized arguments/prefixes (fix) +#328 exclude types when declaredtype is excluded (fix-feature) +#302 ignore branches in known autogenerated sequences (feature) +#310 skip first switch (if applicable) in a generated MoveNext (feature) + +Version 4.6.166 #323 push releases and candidates to github via appveyor (prj-mgmt) #315 update nuget package (fix for VS2015) #320 update packages (fix for VS2015) diff --git a/appveyor.yml b/appveyor.yml index 8b8063600..58d19fbce 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,5 @@ version: 4.6.{build} +skip_tags: true os: Unstable shallow_clone: true environment: @@ -60,4 +61,4 @@ notifications: on_build_failure: true on_build_status_changed: true on_success: -- build dogfood-release \ No newline at end of file +- build dogfood-release diff --git a/build/opencover.build b/build/opencover.build index f9725f7af..c1c4ccf93 100644 --- a/build/opencover.build +++ b/build/opencover.build @@ -1,20 +1,18 @@ - - - - - - - - + + + + + + + + - - - + @@ -26,40 +24,40 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - + + + - - Output file doesn't exist in ${expected.output} - + + Output file doesn't exist in ${expected.output} - - - - - - - - - - - + + + + - - - - - - + + + + + + - + - + - - - - - - - - + + + + + + - + - + - - - + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - + + + + + + + + + - + - + - - - - + + + + + + - + - + - + - + - - - - + + + + + + - + \ No newline at end of file diff --git a/default.build b/default.build index f4b14db91..6ce048f53 100644 --- a/default.build +++ b/default.build @@ -50,7 +50,7 @@ tofile="${solution.folder}/bin/zip/opencover.${buildnumber.major}.${buildnumber.minor}.${buildnumber.build}.zip" /> - + @@ -61,12 +61,7 @@ - - - - - - + @@ -95,6 +90,6 @@ - + \ No newline at end of file diff --git a/main/OpenCover.Console/Program.cs b/main/OpenCover.Console/Program.cs index 38918ff0f..7ec00e6e3 100644 --- a/main/OpenCover.Console/Program.cs +++ b/main/OpenCover.Console/Program.cs @@ -541,7 +541,9 @@ private static bool ParseCommandLine(string[] args, out CommandLineParser parser } catch (Exception ex) { + System.Console.WriteLine(""); System.Console.WriteLine("Incorrect Arguments: {0}", ex.Message); + System.Console.WriteLine(""); System.Console.WriteLine(parser.Usage()); return false; } diff --git a/main/OpenCover.Framework/CommandLineParser.cs b/main/OpenCover.Framework/CommandLineParser.cs index de34a7db1..07220b3d2 100644 --- a/main/OpenCover.Framework/CommandLineParser.cs +++ b/main/OpenCover.Framework/CommandLineParser.cs @@ -145,6 +145,8 @@ public string Usage() /// public void ExtractAndValidateArguments() { + ParseArguments(); + foreach (var key in ParsedArguments.Keys) { var lower = key.ToLowerInvariant(); @@ -247,7 +249,7 @@ public void ExtractAndValidateArguments() PrintVersion = true; break; default: - throw new InvalidOperationException(string.Format("The argument {0} is not recognised", key)); + throw new InvalidOperationException(string.Format("The argument '-{0}' is not recognised", key)); } } diff --git a/main/OpenCover.Framework/CommandLineParserBase.cs b/main/OpenCover.Framework/CommandLineParserBase.cs index 853fc924a..57b968efd 100644 --- a/main/OpenCover.Framework/CommandLineParserBase.cs +++ b/main/OpenCover.Framework/CommandLineParserBase.cs @@ -21,21 +21,29 @@ protected CommandLineParserBase(string[] arguments) { _arguments = arguments; ParsedArguments = new Dictionary(); - ParseArguments(); } protected IDictionary ParsedArguments { get; private set; } - - private void ParseArguments() + + /// + /// Parse the arguments + /// + protected void ParseArguments() { if (_arguments == null) return; + if (ParsedArguments.Count > 0) return; foreach (var argument in _arguments) { var trimmed = argument.Trim(); - if (!trimmed.StartsWith("-")) continue; + if (string.IsNullOrEmpty(trimmed)) continue; + + if (!trimmed.StartsWith("-")) + throw new InvalidOperationException(string.Format("The argument '{0}' is not recognised", argument)); + trimmed = trimmed.Substring(1); if (string.IsNullOrEmpty(trimmed)) continue; + var colonidx = trimmed.IndexOf(':'); if (colonidx>0) { diff --git a/main/OpenCover.Framework/Communication/CommunicationManager.cs b/main/OpenCover.Framework/Communication/CommunicationManager.cs index 15e3a470d..cc2fd44ec 100644 --- a/main/OpenCover.Framework/Communication/CommunicationManager.cs +++ b/main/OpenCover.Framework/Communication/CommunicationManager.cs @@ -16,7 +16,7 @@ public interface ICommunicationManager /// /// /// - void HandleCommunicationBlock(IManagedCommunicationBlock mcb, Action offloadHandling); + void HandleCommunicationBlock(IManagedCommunicationBlock mcb, Action offloadHandling); /// /// process a results block from the profiler @@ -46,7 +46,7 @@ public CommunicationManager(IMessageHandler messageHandler) _messageHandler = messageHandler; } - public void HandleCommunicationBlock(IManagedCommunicationBlock mcb, Action offloadHandling) + public void HandleCommunicationBlock(IManagedCommunicationBlock mcb, Action offloadHandling) { mcb.ProfilerRequestsInformation.Reset(); diff --git a/main/OpenCover.Framework/Communication/MessageHandler.cs b/main/OpenCover.Framework/Communication/MessageHandler.cs index ba3641d84..d8ee26c8b 100644 --- a/main/OpenCover.Framework/Communication/MessageHandler.cs +++ b/main/OpenCover.Framework/Communication/MessageHandler.cs @@ -16,7 +16,7 @@ namespace OpenCover.Framework.Communication { public interface IMessageHandler { - int StandardMessage(MSG_Type msgType, IManagedCommunicationBlock mcb, Action chunkReady, Action offloadHandling); + int StandardMessage(MSG_Type msgType, IManagedCommunicationBlock mcb, Action chunkReady, Action offloadHandling); int ReadSize { get; } void Complete(); } @@ -38,7 +38,7 @@ public MessageHandler(IProfilerCommunication profilerCommunication, IMarshalWrap } // TODO: change pinnedMemory to an byte[], pass in mcb as well - public int StandardMessage(MSG_Type msgType, IManagedCommunicationBlock mcb, Action chunkReady, Action offloadHandling) + public int StandardMessage(MSG_Type msgType, IManagedCommunicationBlock mcb, Action chunkReady, Action offloadHandling) { IntPtr pinnedMemory = mcb.PinnedDataCommunication.AddrOfPinnedObject(); var writeSize = 0; @@ -153,7 +153,20 @@ public int StandardMessage(MSG_Type msgType, IManagedCommunicationBlock mcb, Act writeSize = Marshal.SizeOf(typeof(MSG_AllocateBuffer_Response)); _bufferId++; - offloadHandling(block.Item1, block.Item2); + offloadHandling(block); + } + break; + + case MSG_Type.MSG_CloseChannel: + { + var msgCC = _marshalWrapper.PtrToStructure(pinnedMemory); + var bufferId = msgCC.bufferId; + + var responseCC = new MSG_CloseChannel_Response { done = true }; + _marshalWrapper.StructureToPtr(responseCC, pinnedMemory, false); + writeSize = Marshal.SizeOf(typeof(MSG_CloseChannel_Response)); + + _memoryManager.DeactivateMemoryBuffer(bufferId); } break; } @@ -180,6 +193,8 @@ public int ReadSize Marshal.SizeOf(typeof(MSG_TrackMethod_Response)), Marshal.SizeOf(typeof(MSG_AllocateBuffer_Request)), Marshal.SizeOf(typeof(MSG_AllocateBuffer_Response)), + Marshal.SizeOf(typeof(MSG_CloseChannel_Request)), + Marshal.SizeOf(typeof(MSG_CloseChannel_Response)), }).Max(); } return _readSize; diff --git a/main/OpenCover.Framework/Communication/Messages.cs b/main/OpenCover.Framework/Communication/Messages.cs index 23bc0fb63..6bdfccfef 100644 --- a/main/OpenCover.Framework/Communication/Messages.cs +++ b/main/OpenCover.Framework/Communication/Messages.cs @@ -14,6 +14,7 @@ public enum MSG_Type : int MSG_GetBranchPoints = 3, MSG_TrackMethod = 4, MSG_AllocateMemoryBuffer = 5, + MSG_CloseChannel = 6, } public enum MSG_IdType : uint @@ -132,4 +133,18 @@ public struct MSG_AllocateBuffer_Response public uint bufferId; } + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] + public struct MSG_CloseChannel_Request + { + public MSG_Type type; + public uint bufferId; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct MSG_CloseChannel_Response + { + [MarshalAs(UnmanagedType.Bool)] + public bool done; + } + } diff --git a/main/OpenCover.Framework/Filter.cs b/main/OpenCover.Framework/Filter.cs index b1ff38a39..e15e47d78 100644 --- a/main/OpenCover.Framework/Filter.cs +++ b/main/OpenCover.Framework/Filter.cs @@ -5,6 +5,7 @@ // using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; @@ -152,10 +153,13 @@ public bool ExcludeByAttribute(IMemberDefinition entity) while (true) { - if (entity == null || !entity.HasCustomAttributes) + if (entity == null) return false; - if (ExcludeByAttribute((ICustomAttributeProvider) entity)) + if (ExcludeByAttribute((ICustomAttributeProvider)entity)) + return true; + + if (ExcludeByAttribute(entity.DeclaringType)) return true; if (entity.DeclaringType == null || !entity.Name.StartsWith("<")) diff --git a/main/OpenCover.Framework/Manager/IMemoryManager.cs b/main/OpenCover.Framework/Manager/IMemoryManager.cs index fabe1bc56..a0556f6bd 100644 --- a/main/OpenCover.Framework/Manager/IMemoryManager.cs +++ b/main/OpenCover.Framework/Manager/IMemoryManager.cs @@ -4,10 +4,24 @@ namespace OpenCover.Framework.Manager { + public class ManagedBufferBlock + { + public ManagedBufferBlock() + { + Active = true; + } + public IManagedCommunicationBlock CommunicationBlock { get; set; } + public IManagedMemoryBlock MemoryBlock { get; set; } + public uint BufferId { get; set; } + public bool Active { get; set; } + } + public interface IMemoryManager : IDisposable { void Initialise(string nameSpace, string key, IEnumerable servicePrincipal); - Tuple AllocateMemoryBuffer(int bufferSize, uint bufferId); - IList> GetBlocks { get; } + ManagedBufferBlock AllocateMemoryBuffer(int bufferSize, uint bufferId); + IList GetBlocks { get; } + void DeactivateMemoryBuffer(uint bufferId); + void RemoveDeactivatedBlocks(); } } \ No newline at end of file diff --git a/main/OpenCover.Framework/Manager/MemoryManager.cs b/main/OpenCover.Framework/Manager/MemoryManager.cs index d9d639dc3..116e77276 100644 --- a/main/OpenCover.Framework/Manager/MemoryManager.cs +++ b/main/OpenCover.Framework/Manager/MemoryManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.IO.MemoryMappedFiles; using System.Linq; @@ -19,7 +20,7 @@ public class MemoryManager : IMemoryManager private string _key; private readonly object _lockObject = new object(); - private readonly IList> _blocks = new List>(); + private readonly IList _blocks = new List(); /// /// @@ -118,6 +119,7 @@ internal ManagedMemoryBlock(string @namespace, string key, int bufferSize, int b public void Dispose() { + Debug.WriteLine("*** disposing memory block ***"); StreamAccessorResults.Dispose(); _mmfResults.Dispose(); } @@ -207,6 +209,7 @@ internal ManagedCommunicationBlock(string @namespace, string key, int bufferSize public void Dispose() { + Debug.WriteLine("*** disposing communication block ***"); StreamAccessorComms.Dispose(); _memoryMappedFile.Dispose(); PinnedDataCommunication.Free(); @@ -238,37 +241,75 @@ public void Initialise(string @namespace, string key, IEnumerable servic /// /// /// - public Tuple AllocateMemoryBuffer(int bufferSize, uint bufferId) + public ManagedBufferBlock AllocateMemoryBuffer(int bufferSize, uint bufferId) { if (!_isIntialised) return null; lock (_lockObject) { - var tuple = new Tuple( - new ManagedCommunicationBlock(_namespace, _key, bufferSize, (int)bufferId, _servicePrincipal), - new ManagedMemoryBlock(_namespace, _key, bufferSize, (int)bufferId, _servicePrincipal)); + var tuple = new ManagedBufferBlock + { + CommunicationBlock = + new ManagedCommunicationBlock(_namespace, _key, bufferSize, (int) bufferId, _servicePrincipal), + MemoryBlock = + new ManagedMemoryBlock(_namespace, _key, bufferSize, (int) bufferId, _servicePrincipal), + BufferId = bufferId + }; _blocks.Add(tuple); return tuple; } } + /// /// get a pair of communication+memory blocks /// - public IList> GetBlocks + public IList GetBlocks { get { return _blocks; } } + /// + /// deactivate a memory block + /// + /// + public void DeactivateMemoryBuffer(uint bufferId) + { + lock (_lockObject) + { + var block = _blocks.FirstOrDefault(b => b.BufferId == bufferId); + if (block == null) return; + block.Active = false; + } + } + + /// + /// remove deactivated blocks + /// + public void RemoveDeactivatedBlocks() + { + lock (_lockObject) + { + var list = _blocks.Where(b => !b.Active).ToList(); + foreach (var b in list) + { + Debug.WriteLine("*** removing deactivated ***"); + b.CommunicationBlock.Dispose(); + b.MemoryBlock.Dispose(); + _blocks.RemoveAt(_blocks.IndexOf(b)); + } + } + } + public void Dispose() { //Console.WriteLine("Disposing..."); lock (_lockObject) { - foreach(var block in _blocks) + foreach(var block in _blocks.Where(b => b.Active)) { - block.Item1.Dispose(); - block.Item2.Dispose(); + block.CommunicationBlock.Dispose(); + block.MemoryBlock.Dispose(); } _blocks.Clear(); } diff --git a/main/OpenCover.Framework/Manager/ProfilerManager.cs b/main/OpenCover.Framework/Manager/ProfilerManager.cs index 1d700b8c8..eb062f5f9 100644 --- a/main/OpenCover.Framework/Manager/ProfilerManager.cs +++ b/main/OpenCover.Framework/Manager/ProfilerManager.cs @@ -173,12 +173,12 @@ private void ProcessMessages(WaitHandle[] handles) break; case 1: - _communicationManager.HandleCommunicationBlock(_mcb, (mcb, mmb) => threadHandles.Add(StartProcessingThread(mcb, mmb))); + _communicationManager.HandleCommunicationBlock(_mcb, block => threadHandles.Add(StartProcessingThread(block))); break; } } while (_continueWait); - foreach (var block in _memoryManager.GetBlocks.Select(b => b.Item2)) + foreach (var block in _memoryManager.GetBlocks.Where(b => b.Active).Select(b => b.MemoryBlock)) { var data = new byte[block.BufferSize]; block.StreamAccessorResults.Seek(0, SeekOrigin.Begin); @@ -210,46 +210,46 @@ private void ProcessMessages(WaitHandle[] handles) _messageQueue.Enqueue(new byte[0]); } - private Tuple StartProcessingThread(IManagedCommunicationBlock communicationBlock, IManagedMemoryBlock memoryBlock) + private Tuple StartProcessingThread(ManagedBufferBlock block) { var terminateThread = new ManualResetEvent(false); var threadTerminated = new ManualResetEvent(false); using (var threadActivated = new AutoResetEvent(false)) { - ThreadPool.QueueUserWorkItem(ProcessBlock(communicationBlock, memoryBlock, terminateThread, + ThreadPool.QueueUserWorkItem(ProcessBlock(block, terminateThread, threadActivated, threadTerminated)); threadActivated.WaitOne(); } return new Tuple(terminateThread, threadTerminated); } - private WaitCallback ProcessBlock(IManagedCommunicationBlock communicationBlock, IManagedMemoryBlock memoryBlock, + private WaitCallback ProcessBlock(ManagedBufferBlock block, WaitHandle terminateThread, EventWaitHandle threadActivated, EventWaitHandle threadTerminated) { return state => { var processEvents = new [] { - communicationBlock.ProfilerRequestsInformation, - memoryBlock.ProfilerHasResults, + block.CommunicationBlock.ProfilerRequestsInformation, + block.MemoryBlock.ProfilerHasResults, terminateThread }; threadActivated.Set(); - while(true) + while(block.Active) { switch (WaitHandle.WaitAny(processEvents)) { case 0: - _communicationManager.HandleCommunicationBlock(communicationBlock, (cB, mB) => { }); + _communicationManager.HandleCommunicationBlock(block.CommunicationBlock, b => { }); break; case 1: - var data = _communicationManager.HandleMemoryBlock(memoryBlock); + var data = _communicationManager.HandleMemoryBlock(block.MemoryBlock); // don't let the queue get too big as using too much memory causes // problems i.e. the target process closes down but the host takes // ages to shutdown; this is a compromise. - _messageQueue.Enqueue(data); + _messageQueue.Enqueue(data); if (_messageQueue.Count > 400) { do @@ -263,6 +263,8 @@ private WaitCallback ProcessBlock(IManagedCommunicationBlock communicationBlock, return; } } + threadTerminated.Set(); + _memoryManager.RemoveDeactivatedBlocks(); }; } } diff --git a/main/OpenCover.Framework/Persistance/BasePersistance.cs b/main/OpenCover.Framework/Persistance/BasePersistance.cs index fb284030c..79e57e234 100644 --- a/main/OpenCover.Framework/Persistance/BasePersistance.cs +++ b/main/OpenCover.Framework/Persistance/BasePersistance.cs @@ -489,6 +489,12 @@ public string GetClassFullName(string modulePath, int functionToken) public void SaveVisitData(byte[] data) { var nCount = BitConverter.ToUInt32(data, 0); + if (nCount > (data.Count()/4) - 1) + { + _logger.DebugFormat("Failed to process points as count ({0}) exceeded available buffer size ({1})", + nCount, (data.Count()/4) - 1); + return; + } for (int i = 0, idx = 4; i < nCount; i++, idx += 4) { var spid = BitConverter.ToUInt32(data, idx); diff --git a/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs b/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs index cf65e1c75..fab23a7e0 100644 --- a/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs +++ b/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Mdb; @@ -386,11 +387,19 @@ private void GetBranchPointsForToken(int token, List list) try { UInt32 ordinal = 0; + var instructions = methodDefinition.SafeGetMethodBody().Instructions; + + // if method is generated MoveNext skip switch if it is the first branch + var skipFirstSwitch = Regex.IsMatch(methodDefinition.FullName, @"\<.+\>d__\d+::MoveNext\(\)$"); - foreach (var instruction in methodDefinition.SafeGetMethodBody().Instructions) + foreach (var instruction in instructions.Where(instruction => instruction.OpCode.FlowControl == FlowControl.Cond_Branch)) { - if (instruction.OpCode.FlowControl != FlowControl.Cond_Branch) + if (instruction.OpCode.Code == Code.Switch && skipFirstSwitch) + { + skipFirstSwitch = false; continue; + } + skipFirstSwitch = false; if (BranchIsInGeneratedFinallyBlock(instruction, methodDefinition)) continue; @@ -426,7 +435,6 @@ private void GetBranchPointsForToken(int token, List list) : new List(), EndOffset = pathOffsetList.Last() }; - list.Add(path0); // Add Conditional Branch (Path=1) if (instruction.OpCode.Code != Code.Switch) @@ -452,7 +460,42 @@ private void GetBranchPointsForToken(int token, List list) : new List(), EndOffset = pathOffsetList.Last() }; - list.Add(path1); + + // only add branch if branch does not match a known sequence + // e.g. auto generated field assignment + // or encapsulates at least one sequence point + var offsets = new[] + { + path0.Offset, + path0.EndOffset, + path1.Offset, + path1.EndOffset + }; + + var ignoreSequences = new[] + { + new []{ Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Br_S, Code.Ldsfld}, // CachedAnonymousMethodDelegate field allocation - debug + new []{ Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Ldsfld} // CachedAnonymousMethodDelegate field allocation + }; + + var bs = offsets.Min(); + var be = offsets.Max(); + + var range = instructions.Where(i => (i.Offset >= bs) && (i.Offset <= be)).ToList(); + + var match = ignoreSequences + .Where(ignoreSequence => range.Count() >= ignoreSequence.Count()) + .Select(x => x.Zip(range, (code, i1) => new {Code1 = code, Code2 = i1.OpCode.Code}).All(y => y.Code1 == y.Code2)) + .Any(); + + var count = range + .Count(i => i.SequencePoint != null); + + if (!match || count > 0) + { + list.Add(path0); + list.Add(path1); + } } else // instruction.OpCode.Code == Code.Switch { @@ -460,6 +503,7 @@ private void GetBranchPointsForToken(int token, List list) if (branchInstructions == null || branchInstructions.Length == 0) return; + list.Add(path0); // Add Conditional Branches (Path>0) foreach (var @case in branchInstructions) { @@ -548,7 +592,7 @@ private Instruction FindClosestSequencePoints(MethodBody methodBody, Instruction { var sequencePointsInMethod = methodBody.Instructions.Where(HasValidSequencePoint).ToList(); if (!sequencePointsInMethod.Any()) return null; - var idx = sequencePointsInMethod.BinarySearch(instruction, new InstructionByOffsetCompararer()); + var idx = sequencePointsInMethod.BinarySearch(instruction, new InstructionByOffsetComparer()); Instruction prev; if (idx < 0) { @@ -570,7 +614,7 @@ private bool HasValidSequencePoint(Instruction instruction) return instruction.SequencePoint != null && instruction.SequencePoint.StartLine != StepOverLineCode; } - private class InstructionByOffsetCompararer : IComparer + private class InstructionByOffsetComparer : IComparer { public int Compare(Instruction x, Instruction y) { diff --git a/main/OpenCover.Profiler/CodeCoverage.cpp b/main/OpenCover.Profiler/CodeCoverage.cpp index f2225e315..30b4f119b 100644 --- a/main/OpenCover.Profiler/CodeCoverage.cpp +++ b/main/OpenCover.Profiler/CodeCoverage.cpp @@ -164,9 +164,7 @@ HRESULT STDMETHODCALLTYPE CCodeCoverage::Shutdown( void) if (m_chainedProfiler != NULL) m_chainedProfiler->Shutdown(); - if (!m_tracingEnabled){ - m_host.SendRemainingThreadBuffers(); - } + m_host.CloseChannel(m_tracingEnabled); WCHAR szExeName[MAX_PATH]; GetModuleFileNameW(NULL, szExeName, MAX_PATH); @@ -239,6 +237,12 @@ HRESULT STDMETHODCALLTYPE CCodeCoverage::ModuleAttachedToAssembly( m_allowModules[modulePath] = m_host.TrackAssembly((LPWSTR)modulePath.c_str(), (LPWSTR)assemblyName.c_str()); m_allowModulesAssemblyMap[modulePath] = assemblyName; + if (m_allowModules[modulePath]){ + ATLTRACE(_T("::ModuleAttachedToAssembly(...) => (%X => %s, %X => %s)"), + moduleId, W2CT(modulePath.c_str()), + assemblyId, W2CT(assemblyName.c_str())); + } + return S_OK; } diff --git a/main/OpenCover.Profiler/Messages.h b/main/OpenCover.Profiler/Messages.h index 632ac273a..1c99fbd67 100644 --- a/main/OpenCover.Profiler/Messages.h +++ b/main/OpenCover.Profiler/Messages.h @@ -41,6 +41,7 @@ enum MSG_Type : int MSG_GetBranchPoints = 3, MSG_TrackMethod = 4, MSG_AllocateMemoryBuffer = 5, + MSG_CloseChannel = 6, }; enum MSG_IdType : ULONG @@ -128,6 +129,17 @@ typedef struct _MSG_AllocateBuffer_Response ULONG ulBufferId; } MSG_AllocateBuffer_Response; +typedef struct _MSG_CloseChannel_Request +{ + MSG_Type type; + ULONG ulBufferId; +} MSG_CloseChannel_Request; + +typedef struct _MSG_CloseChannel_Response +{ + BOOL bResponse; +} MSG_CloseChannel_Response; + #pragma pack(pop) typedef union _MSG_Union @@ -143,5 +155,7 @@ typedef union _MSG_Union MSG_TrackMethod_Response trackMethodResponse; MSG_AllocateBuffer_Request allocateBufferRequest; MSG_AllocateBuffer_Response allocateBufferResponse; + MSG_CloseChannel_Request closeChannelBufferRequest; + MSG_CloseChannel_Response closeChannelResponse; } MSG_Union; diff --git a/main/OpenCover.Profiler/ProfilerCommunication.cpp b/main/OpenCover.Profiler/ProfilerCommunication.cpp index 9ff3fcce8..4a14231fc 100644 --- a/main/OpenCover.Profiler/ProfilerCommunication.cpp +++ b/main/OpenCover.Profiler/ProfilerCommunication.cpp @@ -19,6 +19,7 @@ ProfilerCommunication::ProfilerCommunication() { + m_bufferId = 0; } ProfilerCommunication::~ProfilerCommunication() @@ -65,6 +66,8 @@ bool ProfilerCommunication::Initialise(TCHAR *key, TCHAR *ns) stream << bufferId; stream >> memoryKey; + m_bufferId = bufferId; + memoryKey = m_key + memoryKey; m_eventProfilerRequestsInformation.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_SendData_Event_") + memoryKey).c_str()); @@ -106,17 +109,25 @@ void ProfilerCommunication::ThreadCreated(ThreadID threadID, DWORD osThreadID){ ATL::CComCritSecLock lock(m_critThreads); m_threadmap[threadID] = osThreadID; auto p = new MSG_SendVisitPoints_Request(); - ::ZeroMemory(p, sizeof(MSG_SendVisitPoints_Request)); + p->count = 0; + //::ZeroMemory(p, sizeof(MSG_SendVisitPoints_Request)); m_visitmap[osThreadID] = p; } MSG_SendVisitPoints_Request* ProfilerCommunication::GetVisitMapForOSThread(ULONG osThreadID){ try { - return m_visitmap[osThreadID]; + auto result = m_visitmap.find(osThreadID); + if (result != m_visitmap.end()) + return (*result).second; + + auto p = new MSG_SendVisitPoints_Request(); + ::ZeroMemory(p, sizeof(MSG_SendVisitPoints_Request)); + m_visitmap[osThreadID] = p; } catch (...){ auto p = new MSG_SendVisitPoints_Request(); - ::ZeroMemory(p, sizeof(MSG_SendVisitPoints_Request)); + p->count = 0; + //::ZeroMemory(p, sizeof(MSG_SendVisitPoints_Request)); m_visitmap[osThreadID] = p; } return m_visitmap[osThreadID]; @@ -125,15 +136,18 @@ MSG_SendVisitPoints_Request* ProfilerCommunication::GetVisitMapForOSThread(ULONG void ProfilerCommunication::ThreadDestroyed(ThreadID threadID){ ATL::CComCritSecLock lock(m_critThreads); ULONG osThreadId = m_threadmap[threadID]; - SendThreadVisitPoints(m_visitmap[osThreadId]); + auto points = m_visitmap[osThreadId]; + SendThreadVisitPoints(points); delete m_visitmap[osThreadId]; m_visitmap[osThreadId] = NULL; } void ProfilerCommunication::SendRemainingThreadBuffers(){ for (auto it = m_visitmap.begin(); it != m_visitmap.end(); ++it){ - if (it->second != NULL) + if (it->second != NULL){ SendThreadVisitPoints(it->second); + //::ZeroMemory(pVisitPoints, sizeof(MSG_SendVisitPoints_Request)); + } } } @@ -145,8 +159,7 @@ void ProfilerCommunication::AddVisitPointToThreadBuffer(ULONG uniqueId, MSG_IdTy if (++pVisitPoints->count == VP_BUFFER_SIZE) { SendThreadVisitPoints(pVisitPoints); - //::ZeroMemory(pVisitPoints, sizeof(MSG_SendVisitPoints_Request)); - pVisitPoints->count = 0; + //::ZeroMemory(pVisitPoints, sizeof(MSG_SendVisitPoints_Request)); } } @@ -154,8 +167,9 @@ void ProfilerCommunication::SendThreadVisitPoints(MSG_SendVisitPoints_Request* p ATL::CComCritSecLock lock(m_critResults); if (!hostCommunicationActive) return; memcpy(m_pVisitPoints, pVisitPoints, sizeof(MSG_SendVisitPoints_Request)); + pVisitPoints->count = 0; SendVisitPoints(); - ::ZeroMemory(m_pVisitPoints, sizeof(MAX_MSG_SIZE)); + //::ZeroMemory(m_pVisitPoints, sizeof(MSG_SendVisitPoints_Request)); m_pVisitPoints->count = 0; } @@ -167,7 +181,7 @@ void ProfilerCommunication::AddVisitPointToBuffer(ULONG uniqueId, MSG_IdType msg if (++m_pVisitPoints->count == VP_BUFFER_SIZE) { SendVisitPoints(); - ::ZeroMemory(m_pVisitPoints, sizeof(MAX_MSG_SIZE)); + //::ZeroMemory(m_pVisitPoints, sizeof(MSG_SendVisitPoints_Request)); m_pVisitPoints->count = 0; } } @@ -333,6 +347,36 @@ bool ProfilerCommunication::AllocateBuffer(LONG bufferSize, ULONG &bufferId) return response; } +void ProfilerCommunication::CloseChannel(bool sendSingleBuffer){ + if (m_bufferId == 0) return; + + + if (sendSingleBuffer) + SendVisitPoints(); + else + SendRemainingThreadBuffers(); + + if (!hostCommunicationActive) return; + + bool response = false; + + RequestInformation( + [=]() + { + m_pMSG->closeChannelBufferRequest.type = MSG_CloseChannel; + m_pMSG->closeChannelBufferRequest.ulBufferId = m_bufferId; + }, + [=, &response]()->BOOL + { + response = m_pMSG->allocateBufferResponse.bResponse == TRUE; + return FALSE; + } + , COMM_WAIT_SHORT + , _T("CloseChannel")); + + return; +} + template void ProfilerCommunication::RequestInformation(BR buildRequest, PR processResults, DWORD dwTimeout, tstring message) { diff --git a/main/OpenCover.Profiler/ProfilerCommunication.h b/main/OpenCover.Profiler/ProfilerCommunication.h index d161c6e3b..54e9e5d56 100644 --- a/main/OpenCover.Profiler/ProfilerCommunication.h +++ b/main/OpenCover.Profiler/ProfilerCommunication.h @@ -35,11 +35,11 @@ class ProfilerCommunication inline void AddTestTailcallPoint(ULONG uniqueId) { AddVisitPointToBuffer(uniqueId, IT_MethodTailcall); } inline void AddVisitPoint(ULONG uniqueId) { AddVisitPointToBuffer(uniqueId, IT_VisitPoint); } void AddVisitPointToThreadBuffer(ULONG uniqueId, MSG_IdType msgType); + void CloseChannel(bool sendSingleBuffer); public: void ThreadCreated(ThreadID threadID, DWORD osThreadID); void ThreadDestroyed(ThreadID threadID); - void SendRemainingThreadBuffers(); private: void AddVisitPointToBuffer(ULONG uniqueId, MSG_IdType msgType); @@ -47,6 +47,7 @@ class ProfilerCommunication void SendThreadVisitPoints(MSG_SendVisitPoints_Request* pVisitPoints); bool GetSequencePoints(mdToken functionToken, WCHAR* pModulePath, WCHAR* pAssemblyName, std::vector &points); bool GetBranchPoints(mdToken functionToken, WCHAR* pModulePath, WCHAR* pAssemblyName, std::vector &points); + void SendRemainingThreadBuffers(); private: tstring m_key; @@ -55,6 +56,8 @@ class ProfilerCommunication template void RequestInformation(BR buildRequest, PR processResults, DWORD dwTimeout, tstring message); + ULONG m_bufferId; + private: CMutex m_mutexCommunication; CSharedMemory m_memoryCommunication; diff --git a/main/OpenCover.Simple.Target/OpenCover.Simple.Target.csproj b/main/OpenCover.Simple.Target/OpenCover.Simple.Target.csproj index d2fb41d11..dde3c75c6 100644 --- a/main/OpenCover.Simple.Target/OpenCover.Simple.Target.csproj +++ b/main/OpenCover.Simple.Target/OpenCover.Simple.Target.csproj @@ -88,6 +88,10 @@ + + mkdir "$(TargetDir)..\..\test" +copy "$(TargetDir)$(TargetName).*" "$(TargetDir)..\..\test" +