예제 #1
0
        public Allocation(AllocationData data)
        {
            MessageDescriptor d = AllocationData.Descriptor;

            foreach (FieldDescriptor f in d.Fields)
            {
                fields.Add(f.Name, data[f]);
            }

            this.id = this[ALLOCATION_ID];
        }
예제 #2
0
        /// <summary>
        /// Returns the allocation block with the given addresses.
        /// </summary>
        /// <param name="address1">The trace 1 address to be searched for.</param>
        /// <param name="address2">The trace 2 address to be searched for.</param>
        private AllocationData FindAllocationBlock(ulong address1, ulong address2)
        {
            // Find by start address
            // The blocks are sorted by start address, so the first hit should be the right one - else the correct block does not exist
            // TODO In all tests this list stayed quite small, implement it in O(log n) anyway?
            // AllocationData candidate = _allocs.Last(a => a.Key <= address1).Value;
            AllocationData candidate = null;

            for (int i = _allocs.Count - 1; i >= 0; --i)
            {
                if (_allocs.Keys[i] <= address1)
                {
                    candidate = _allocs.Values[i];
                    if (address1 <= candidate.EndAddress1 && candidate.StartAddress2 <= address2 && address2 <= candidate.EndAddress2)
                    {
                        return(candidate);
                    }
                    break;
                }
            }
            return(null);
        }
예제 #3
0
        /// <summary>
        /// Encodes all entries of the given trace file as 64-bit integers. This implies a loss of information.
        /// The least significant 4 bits of each entry will contain the entry type (directly casted from <see cref="TraceEntryTypes"/>).
        /// </summary>
        /// <param name="traceFile">The trace file to be encoded.</param>
        /// <returns>A list of encoded trace entries.</returns>
        public static IEnumerable <long> EncodeTraceEntries(TraceFile traceFile)
        {
            // Initialize stack memory allocation block
            AllocationData stackMemory = new AllocationData
            {
                AllocationLineNumber = 0,
                FreeLineNumber       = traceFile.EntryCount, // Never freed
                StartAddress         = traceFile.StackPointerMin,
                EndAddress           = traceFile.StackPointerMax
            };

            // Run through entries
            int line = 0;
            SortedList <int, AllocationData> allocs = new SortedList <int, AllocationData>();

            foreach (TraceEntry entry in traceFile.Entries)
            {
                // Encode type right away
                ulong enc = (ulong)entry.EntryType;
                switch (entry.EntryType)
                {
                case TraceEntryTypes.Allocation:
                {
                    // Save allocation data
                    AllocationEntry allocationEntry = (AllocationEntry)entry;
                    allocs[line] = new AllocationData()
                    {
                        AllocationLineNumber = line,
                        FreeLineNumber       = traceFile.EntryCount, // First assume as never freed, is overwritten as soon as a matching free is encountered
                        StartAddress         = allocationEntry.Address,
                        EndAddress           = allocationEntry.Address + allocationEntry.Size
                    };

                    // Encode allocation size
                    enc |= (ulong)allocationEntry.Size << 4;
                    break;
                }

                case TraceEntryTypes.Free:
                {
                    // Find corresponding allocation block to mark as freed
                    FreeEntry freeEntry       = (FreeEntry)entry;
                    var       allocCandidates = allocs.Where(a => a.Key <= line && a.Value.FreeLineNumber >= line && a.Value.StartAddress == freeEntry.Address);
                    if (!allocCandidates.Any())
                    {
                        // TODO Error handling (same problem as in TraceFileComparer)
                        //Debug.WriteLine($"Warning! Processing line {line}: Skipped free() without any matching allocation block.");
                    }
                    else
                    {
                        // Mark block as freed
                        AllocationData allocData = allocCandidates.First().Value;
                        allocData.FreeLineNumber = line;
                    }

                    // Not encoded
                    break;
                }

                case TraceEntryTypes.ImageMemoryRead:
                {
                    // Encode instruction and address offset
                    ImageMemoryReadEntry imageMemoryReadEntry = (ImageMemoryReadEntry)entry;
                    enc |= imageMemoryReadEntry.InstructionAddress << 4;
                    enc |= (ulong)imageMemoryReadEntry.MemoryAddress << 32;
                    break;
                }

                case TraceEntryTypes.ImageMemoryWrite:
                {
                    // Encode instruction and address offset
                    ImageMemoryWriteEntry imageMemoryWriteEntry = (ImageMemoryWriteEntry)entry;
                    enc |= imageMemoryWriteEntry.InstructionAddress << 4;
                    enc |= (ulong)imageMemoryWriteEntry.MemoryAddress << 32;
                    break;
                }

                case TraceEntryTypes.AllocMemoryRead:
                {
                    // Find related allocation block
                    // Stack or heap?
                    AllocMemoryReadEntry allocMemoryReadEntry = (AllocMemoryReadEntry)entry;
                    AllocationData       allocData            = stackMemory;
                    if (allocMemoryReadEntry.MemoryAddress < stackMemory.StartAddress || stackMemory.EndAddress < allocMemoryReadEntry.MemoryAddress)
                    {
                        // Heap?
                        var allocCandidates = allocs.Where(a => a.Key <= line && a.Value.FreeLineNumber >= line && a.Value.StartAddress <= allocMemoryReadEntry.MemoryAddress && allocMemoryReadEntry.MemoryAddress <= a.Value.EndAddress);
                        if (!allocCandidates.Any())
                        {
                            // TODO error handling - caused by missed malloc()
                            //Program.Log($"Error: Could not find allocation block for [{line}] {allocMemoryReadEntry.ToString()}\n", Program.LogLevel.Error);
                            Debug.WriteLine($"Error: Could not find allocation block for [{line}] {allocMemoryReadEntry.ToString()}");
                            break;
                        }
                        else
                        {
                            allocData = allocCandidates.Last().Value;
                        }
                    }

                    // Encode instruction address, the size of the allocation block, and the offset
                    enc |= allocMemoryReadEntry.InstructionAddress << 4;
                    enc |= (allocMemoryReadEntry.MemoryAddress - allocData.StartAddress) << 32;
                    //enc |= (allocData.EndAddress - allocData.StartAddress) << 48; // Only catches sizes less than 64 KB (16 bit address space)
                    break;
                }

                case TraceEntryTypes.AllocMemoryWrite:
                {
                    // Find related allocation block
                    // Stack or heap?
                    AllocMemoryWriteEntry allocMemoryWriteEntry = (AllocMemoryWriteEntry)entry;
                    AllocationData        allocData             = stackMemory;
                    if (allocMemoryWriteEntry.MemoryAddress < stackMemory.StartAddress || stackMemory.EndAddress < allocMemoryWriteEntry.MemoryAddress)
                    {
                        // Heap?
                        var allocCandidates = allocs.Where(a => a.Key <= line && a.Value.FreeLineNumber >= line && a.Value.StartAddress <= allocMemoryWriteEntry.MemoryAddress && allocMemoryWriteEntry.MemoryAddress <= a.Value.EndAddress);
                        if (!allocCandidates.Any())
                        {
                            // TODO error handling - caused by missed malloc()
                            //Program.Log($"Error: Could not find allocation block for [{line}] {allocMemoryWriteEntry.ToString()}\n", Program.LogLevel.Error);
                            Debug.WriteLine($"Error: Could not find allocation block for [{line}] {allocMemoryWriteEntry.ToString()}");
                            break;
                        }
                        else
                        {
                            allocData = allocCandidates.Last().Value;
                        }
                    }

                    // Encode instruction address, the size of the allocation block, and the offset
                    enc |= allocMemoryWriteEntry.InstructionAddress << 4;
                    enc |= (allocMemoryWriteEntry.MemoryAddress - allocData.StartAddress) << 32;
                    //enc |= (allocData.EndAddress - allocData.StartAddress) << 48; // Only catches sizes less than 64 KB (16 bit address space)
                    break;
                }

                case TraceEntryTypes.Branch:
                {
                    // Encode branch source and destination image offsets, and the "taken" flag
                    BranchEntry branchEntry = (BranchEntry)entry;
                    enc |= branchEntry.SourceInstructionAddress << 4;
                    enc |= (ulong)branchEntry.DestinationInstructionAddress << 32;
                    enc |= (ulong)(branchEntry.Taken ? 1 : 0) << 63;
                    break;
                }
                }
                yield return(unchecked ((long)enc));

                ++line;
            }
        }
        private async Task SearchDataAsync()
        {
            try
            {
                if (string.IsNullOrWhiteSpace(SubNo))
                {
                    return;
                }
                if (string.IsNullOrWhiteSpace(SelectedMasterAwb))
                {
                    await Application.Current.MainPage.DisplayAlert("提示", "选择主单号", "确定");

                    return;
                }
                var rst        = App.Allocations.Where(p => p.MasterAwb == SelectedMasterAwb && p.SubAwb == SubNo.TrimEnd());
                var enumerable = rst as AllocationData[] ?? rst.ToArray();
                if (enumerable.Any())
                {
                    var firstItem = enumerable.First();
                    // 如果已经盘点过就不要再进行盘点
                    if (firstItem.IsChecked != StateKind.Checked)
                    {
                        //清理
                        Allots.Clear();
                        firstItem.IsChecked = StateKind.Checked;

                        App.Allocations.First(p => p.MasterAwb == SelectedMasterAwb && p.SubAwb == SubNo).IsChecked =
                            StateKind.Checked;
                        //更新缓存中的数据,因为需要同步到服务器上
                        //App.CheckedAllocations.First(p => p.MasterAwb == SelectedMasterAwb && p.SubAwb == SubNo).IsChecked =
                        //    StateKind.Checked;
                        if (App.CheckedAllocations.Contains(firstItem))
                        {
                            foreach (var data in App.CheckedAllocations)
                            {
                                if (data.MasterAwb == SelectedMasterAwb && data.SubAwb == SubNo)
                                {
                                    data.IsChecked = StateKind.Checked;
                                }
                            }
                        }
                        else
                        {
                            App.CheckedAllocations.Push(firstItem);
                        }
                        //这个是持久化保存,就是防止手持设备突然退出时候,数据能够备份
                        _realm.Write(() =>
                        {
                            var first = _realm.All <AllocationData2>().FirstOrDefault(p => p.MasterAwb == SelectedMasterAwb && p.SubAwb == SubNo);
                            if (first != null)
                            {
                                first.IsChecked = 2;
                            }
                            else
                            {
                                _realm.Add(new AllocationData2
                                {
                                    Amount    = firstItem.Amount,
                                    IsChecked = (int)firstItem.IsChecked,
                                    MasterAwb = firstItem.MasterAwb,
                                    SubAwb    = firstItem.SubAwb,
                                });
                            }
                        });

                        //判断是否需要查验
                        if (!string.IsNullOrWhiteSpace(firstItem.Status) && firstItem.Status.Contains("查验"))
                        {
                            chayanPlayer.Play();
                        }
                        else
                        {
                            okPlayer.Play();
                        }

                        Allots.Add(firstItem);
                        ScanedCount = ScanedCount + 1;
                        Count       = Allots.Count;
                    }
                }
                else
                {
                    //新增
                    yizhuangPlayer.Play();
                    //http://101.201.28.235:91/version/nodata.wav
                    //await CrossMediaManager.Current.Play("http://101.201.28.235:91/version/nodata.wav");
                    if (await Application.Current.MainPage.DisplayAlert("提示", "是否标记为溢装到货", "确定", "取消"))
                    {
                        Allots.Clear();
                        var newItem = new AllocationData
                        {
                            IsChecked = StateKind.OverChecked,
                            MasterAwb = SelectedMasterAwb,
                            SubAwb    = SubNo,
                            Amount    = 1
                        };
                        Allots.Add(newItem);
                        Count = allots.Count;
                        App.Allocations.Add(newItem);
                        App.CheckedAllocations.Push(newItem);
                        ScanedCount = ScanedCount + 1;
                        //添加到本地数据库
                        _realm.Write(() =>
                        {
                            _realm.Add(new AllocationData2
                            {
                                Amount    = 1,
                                IsChecked = 3,
                                MasterAwb = SelectedMasterAwb,
                                SubAwb    = SubNo,
                            });
                        });
                    }
                }
                //TODO: 需要找到扫码完成之后选中文本
                SubNo = string.Empty;
                OnPropertyChanged(nameof(Summary));
            }
            catch (Exception ex)
            {
                await Application.Current.MainPage.DisplayAlert("提示", $"盘点出错:{ex.Message}", "确定");
            }
        }
예제 #5
0
        /// <summary>
        /// Executes the comparison and returns whether the two traces have identical memory access patterns.
        /// </summary>
        /// <returns></returns>
        public bool Compare()
        {
            // Run linearily through trace entries and compare them
            // If the traces have different length, use the shorter one as reference
            // This should not lead to wrong results: The shorter trace won't just randomly end, instead there has to be some kind of branch mismatch before
            // Keep track of currently allocated datablocks
            AllocationData stackMemory = new AllocationData() // StartAddress = Top of stack, EndAddress = Bottom of stack
            {
                StartAddress1 = TraceFile1.StackPointerMin,
                StartAddress2 = TraceFile2.StackPointerMin,
                EndAddress1   = TraceFile1.StackPointerMax,
                EndAddress2   = TraceFile2.StackPointerMax
            };
            int totalEntries         = Math.Min(TraceFile1.EntryCount, TraceFile2.EntryCount);
            var traceFile1Enumerator = TraceFile1.Entries.GetEnumerator();
            var traceFile2Enumerator = TraceFile2.Entries.GetEnumerator();

            for (int i = 0; i < totalEntries; ++i)
            {
                // Retrieve entries
                traceFile1Enumerator.MoveNext();
                traceFile2Enumerator.MoveNext();
                TraceEntry e1 = traceFile1Enumerator.Current;
                TraceEntry e2 = traceFile2Enumerator.Current;

                // The entries should have the same type
                // If not, something must have gone very wrong: Differing branches are detected, so we should not run into differing instructions
                if (e1.EntryType != e2.EntryType)
                {
                    Result = ComparisonResults.ExecutionFlow_DifferentType;
                    ComparisonErrorLine  = i;
                    ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                    if (PrintResults)
                    {
                        PrintComparisonResult($"Entries #{i} have different type (probably some bigger error occured?).", false,
                                              $"Trace 1: {e1.ToString()}",
                                              $"Trace 2: {e2.ToString()}");
                    }
                    return(false);
                }

                // Act depending on entry types
                switch (e1.EntryType)
                {
                // Possible leakages:
                // - Different branch targets
                // - In one execution the branch is taken, in the other one not
                case TraceEntryTypes.Branch:
                {
                    // Cast entries
                    BranchEntry branch1 = (BranchEntry)e1;
                    BranchEntry branch2 = (BranchEntry)e2;

                    // Compare targets
                    if (branch1.DestinationImageId != branch2.DestinationImageId || branch1.DestinationInstructionAddress != branch2.DestinationInstructionAddress)
                    {
                        Result = ComparisonResults.ExecutionFlow_DifferentBranchTarget;
                        ComparisonErrorLine  = i;
                        ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                        if (PrintResults)
                        {
                            PrintComparisonResult($"Entries #{i}: Different branch target: <{branch1.DestinationImageName}+{branch1.DestinationInstructionAddress.ToString("X8")}> vs. <{branch2.DestinationImageName}+{branch2.DestinationInstructionAddress.ToString("X8")}>", false,
                                                  $"Trace 1: {e1.ToString()}",
                                                  $"Trace 2: {e2.ToString()}");
                        }
                        return(false);
                    }

                    // Compare "taken"
                    if (branch1.Taken != branch2.Taken)
                    {
                        if (branch1.Taken)
                        {
                            Result = ComparisonResults.ExecutionFlow_BranchTakenIn1;
                            ComparisonErrorLine  = i;
                            ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                            if (PrintResults)
                            {
                                PrintComparisonResult($"Entries #{i}: Branch to <{branch1.DestinationImageName}+{branch1.DestinationInstructionAddress.ToString("X8")}> taken in trace 1, but not in trace 2.", false,
                                                      $"Trace 1: {e1.ToString()}",
                                                      $"Trace 2: {e2.ToString()}");
                            }
                        }
                        else
                        {
                            Result = ComparisonResults.ExecutionFlow_BranchTakenIn2;
                            ComparisonErrorLine  = i;
                            ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                            if (PrintResults)
                            {
                                PrintComparisonResult($"Entries #{i}: Branch to <{branch1.DestinationImageName}+{branch1.DestinationInstructionAddress.ToString("X8")}> not taken in trace 1, but in trace 2.", false,
                                                      $"Trace 1: {e1.ToString()}",
                                                      $"Trace 2: {e2.ToString()}");
                            }
                        }
                        return(false);
                    }

                    // OK
                    break;
                }

                // Store allocation metadata
                // Possible leakages:
                // - The allocation size might differ
                case TraceEntryTypes.Allocation:
                {
                    // Cast entries
                    AllocationEntry alloc1 = (AllocationEntry)e1;
                    AllocationEntry alloc2 = (AllocationEntry)e2;

                    // Compare sizes
                    if (alloc1.Size != alloc2.Size)
                    {
                        Result = ComparisonResults.MemoryAccess_DifferentAllocationSize;
                        ComparisonErrorLine  = i;
                        ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                        if (PrintResults)
                        {
                            PrintComparisonResult($"Entries #{i}: Allocation size differs: {alloc1.Size} vs. {alloc2.Size}", false,
                                                  $"Trace 1: {e1.ToString()}",
                                                  $"Trace 2: {e2.ToString()}");
                        }
                        return(false);
                    }

                    // Save allocation data
                    _allocs[alloc1.Address] = new AllocationData()
                    {
                        StartAddress1 = alloc1.Address,
                        EndAddress1   = alloc1.Address + alloc1.Size,
                        StartAddress2 = alloc2.Address,
                        EndAddress2   = alloc2.Address + alloc2.Size
                    };

                    // OK
                    break;
                }

                // Remove allocation metadata from list
                case TraceEntryTypes.Free:
                {
                    // Cast entries
                    FreeEntry free1 = (FreeEntry)e1;
                    FreeEntry free2 = (FreeEntry)e2;

                    // Make sure the frees apply to the same datablock
                    if (!_allocs.TryGetValue(free1.Address, out AllocationData freeCandidate))
                    {
                        /*Result = ComparisonResults.MemoryAccess_FreedBlockNotFound;
                         * ComparisonErrorLine = i;
                         * PrintComparisonResult($"Entries #{i}: Cannot find freed allocation block for execution trace 1.", false,
                         *  $"Trace 1: {e1.ToString()}",
                         *  $"Trace 2: {e2.ToString()}");
                         * // TODO This line is triggered in the Alloc/Free prefix, when one malloc() call was missed
                         * return false;*/
                    }
                    else if (freeCandidate.StartAddress2 != free2.Address)
                    {
                        Result = ComparisonResults.MemoryAccess_FreedBlockNotMatching;
                        ComparisonErrorLine  = i;
                        ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                        if (PrintResults)
                        {
                            PrintComparisonResult($"Entries #{i}: Freed allocation block of execution trace 1 does not match freed block of execution trace 2.", false,
                                                  $"Trace 1: {e1.ToString()}",
                                                  $"Trace 2: {e2.ToString()}");
                        }
                        return(false);
                    }
                    else
                    {
                        // OK, remove allocation block
                        _allocs.Remove(free1.Address);
                    }
                    break;
                }

                // Possible leakages:
                // -> Different access offset in image
                case TraceEntryTypes.ImageMemoryRead:
                {
                    // Cast entries
                    ImageMemoryReadEntry read1 = (ImageMemoryReadEntry)e1;
                    ImageMemoryReadEntry read2 = (ImageMemoryReadEntry)e2;

                    // Compare relative access offsets
                    if (read1.MemoryAddress != read2.MemoryAddress)
                    {
                        Result = ComparisonResults.MemoryAccess_DifferentImageMemoryReadOffset;
                        ComparisonErrorLine  = i;
                        ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                        if (PrintResults)
                        {
                            PrintComparisonResult($"Entries #{i}: Memory read offsets in image differ: {read1.MemoryImageName}+{read1.MemoryAddress.ToString("X")} vs. {read2.MemoryImageName}+{read2.MemoryAddress.ToString("X")}", false,
                                                  $"Trace 1: {e1.ToString()}",
                                                  $"Trace 2: {e2.ToString()}");
                        }
                        return(false);
                    }

                    // OK
                    break;
                }

                // Possible leakages:
                // -> Different access offset in image
                case TraceEntryTypes.ImageMemoryWrite:
                {
                    // Cast entries
                    ImageMemoryWriteEntry write1 = (ImageMemoryWriteEntry)e1;
                    ImageMemoryWriteEntry write2 = (ImageMemoryWriteEntry)e2;

                    // Compare relative access offsets
                    if (write1.MemoryAddress != write2.MemoryAddress)
                    {
                        Result = ComparisonResults.MemoryAccess_DifferentImageMemoryWriteOffset;
                        ComparisonErrorLine  = i;
                        ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                        if (PrintResults)
                        {
                            PrintComparisonResult($"Entries #{i}: Memory write offsets in image differ: {write1.MemoryImageName}+{write1.MemoryAddress.ToString("X")} vs. {write2.MemoryImageName}+{write2.MemoryAddress.ToString("X")}", false,
                                                  $"Trace 1: {e1.ToString()}",
                                                  $"Trace 2: {e2.ToString()}");
                        }
                        return(false);
                    }

                    // OK
                    break;
                }

                // Possible leakages:
                // -> Different access offset (after subtracting allocation base addresses)
                case TraceEntryTypes.AllocMemoryRead:
                {
                    // Cast entries
                    AllocMemoryReadEntry read1 = (AllocMemoryReadEntry)e1;
                    AllocMemoryReadEntry read2 = (AllocMemoryReadEntry)e2;

                    // Find related allocation block
                    AllocationData allocCandidate = FindAllocationBlock(read1.MemoryAddress, read2.MemoryAddress);
                    if (allocCandidate == null)
                    {
                        // Stack access?
                        if (stackMemory.StartAddress1 <= read1.MemoryAddress && read1.MemoryAddress <= stackMemory.EndAddress1 &&
                            stackMemory.StartAddress2 <= read2.MemoryAddress && read2.MemoryAddress <= stackMemory.EndAddress2)
                        {
                            allocCandidate = stackMemory;
                        }
                        else
                        {
                            // TODO remove warning, better include the fs/gs segment bounds in the trace
                            if (PrintResults)
                            {
                                PrintComparisonResult($"Entries #{i}: Cannot find common accessed allocation block. Maybe there are segment registers involved?", true,
                                                      $"Trace 1: {read1.ToString()}",
                                                      $"Trace 2: {read2.ToString()}",
                                                      $"Stack: {stackMemory.ToString()}");
                            }
                            break;
                        }
                    }

                    // Calculate and compare relative access offsets
                    ulong offset1 = read1.MemoryAddress - allocCandidate.StartAddress1;
                    ulong offset2 = read2.MemoryAddress - allocCandidate.StartAddress2;
                    if (offset1 != offset2)
                    {
                        Result = ComparisonResults.MemoryAccess_DifferentAllocMemoryReadOffset;
                        ComparisonErrorLine  = i;
                        ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                        if (PrintResults)
                        {
                            PrintComparisonResult($"Entries #{i}: Memory read offsets in common allocation block differ: +{offset1.ToString("X8")} vs. +{offset2.ToString("X8")}", false,
                                                  $"Trace 1: {e1.ToString()}",
                                                  $"Trace 2: {e2.ToString()}");
                        }
                        return(false);
                    }

                    // OK
                    break;
                }

                // Possible leakages:
                // -> Different access offset (after subtracting allocation/stack pointer base addresses)
                case TraceEntryTypes.AllocMemoryWrite:
                {
                    // Cast entries
                    AllocMemoryWriteEntry write1 = (AllocMemoryWriteEntry)e1;
                    AllocMemoryWriteEntry write2 = (AllocMemoryWriteEntry)e2;

                    // Find related allocation block
                    AllocationData allocCandidate = FindAllocationBlock(write1.MemoryAddress, write2.MemoryAddress);
                    if (allocCandidate == null)
                    {
                        // Stack access?
                        if (stackMemory.StartAddress1 <= write1.MemoryAddress && write1.MemoryAddress <= stackMemory.EndAddress1 &&
                            stackMemory.StartAddress2 <= write2.MemoryAddress && write2.MemoryAddress <= stackMemory.EndAddress2)
                        {
                            allocCandidate = stackMemory;
                        }
                        else
                        {
                            // TODO remove warning, better include the fs/gs segment bounds in the trace
                            if (PrintResults)
                            {
                                PrintComparisonResult($"Entries #{i}: Cannot find common accessed allocation block. Maybe there are segment registers involved?", true,
                                                      $"Trace 1: {write1.ToString()}",
                                                      $"Trace 2: {write2.ToString()}",
                                                      $"Stack: {stackMemory.ToString()}");
                            }
                            break;
                        }
                    }

                    // Calculate and compare relative access offsets
                    ulong offset1 = write1.MemoryAddress - allocCandidate.StartAddress1;
                    ulong offset2 = write2.MemoryAddress - allocCandidate.StartAddress2;
                    if (offset1 != offset2)
                    {
                        Result = ComparisonResults.MemoryAccess_DifferentAllocMemoryWriteOffset;
                        ComparisonErrorLine  = i;
                        ComparisonErrorItems = new Tuple <TraceEntry, TraceEntry>(e1, e2);
                        if (PrintResults)
                        {
                            PrintComparisonResult($"Entries #{i}: Memory write offsets in common allocation block differ: +{offset1.ToString("X8")} vs. +{offset2.ToString("X8")}", false,
                                                  $"Trace 1: {e1.ToString()}",
                                                  $"Trace 2: {e2.ToString()}");
                        }
                        return(false);
                    }

                    // OK
                    break;
                }
                }
            }

            // No differences found
            Result = ComparisonResults.Match;
            return(true);
        }