From a9d14ca29e5c15e17ba13e7c93090a72df4c5a97 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 20 Sep 2019 12:10:23 -0700 Subject: [PATCH 1/4] Make the history file mutext name unique across sessions --- PSReadLine/History.cs | 61 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/PSReadLine/History.cs b/PSReadLine/History.cs index 405c36af..0bd45b6f 100644 --- a/PSReadLine/History.cs +++ b/PSReadLine/History.cs @@ -15,6 +15,65 @@ namespace Microsoft.PowerShell { + /// + /// A simple implementation of CRC32. + /// See "CRC-32 algorithm" in https://en.wikipedia.org/wiki/Cyclic_redundancy_check. + /// + internal class CRC32Hash + { + // CRC-32C polynomial representations + private const uint polynomial = 0x1EDC6F41; + private static uint[] table; + + static CRC32Hash() + { + uint temp = 0; + table = new uint[256]; + + for (int i = 0; i < table.Length; i++) + { + temp = (uint)i; + for (int j = 0; j < 8; j++) + { + if ((temp & 1) == 1) + { + temp = (temp >> 1) ^ polynomial; + } + else + { + temp >>= 1; + } + } + + table[i] = temp; + } + } + + private static uint Compute(byte[] buffer) + { + uint crc = 0xFFFFFFFF; + for (int i = 0; i < buffer.Length; ++i) + { + var index = (byte)(crc ^ buffer[i] & 0xff); + crc = (crc >> 8) ^ table[index]; + } + + return ~crc; + } + + internal static byte[] ComputeHash(byte[] buffer) + { + uint crcResult = Compute(buffer); + return BitConverter.GetBytes(crcResult); + } + + internal static string ComputeHash(string input) + { + byte[] hashBytes = ComputeHash(Encoding.UTF8.GetBytes(input)); + return BitConverter.ToString(hashBytes).Replace("-", string.Empty); + } + } + public partial class PSConsoleReadLine { /// @@ -182,7 +241,7 @@ private string GetHistorySaveFileMutexName() { // Return a reasonably unique name - it's not too important as there will rarely // be any contention. - return "PSReadLineHistoryFile_" + _options.HistorySavePath.GetHashCode(); + return "PSReadLineHistoryFile_" + CRC32Hash.ComputeHash(_options.HistorySavePath); } private void IncrementalHistoryWrite() From a241e352cd7bf7c2faa936452a5a04fcbe8cf5f0 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 23 Sep 2019 12:58:11 -0700 Subject: [PATCH 2/4] Use FNV-1a hashing algorithm instead --- PSReadLine/History.cs | 60 ++++++++++--------------------------------- 1 file changed, 13 insertions(+), 47 deletions(-) diff --git a/PSReadLine/History.cs b/PSReadLine/History.cs index 0bd45b6f..75c2da7e 100644 --- a/PSReadLine/History.cs +++ b/PSReadLine/History.cs @@ -16,61 +16,27 @@ namespace Microsoft.PowerShell { /// - /// A simple implementation of CRC32. - /// See "CRC-32 algorithm" in https://en.wikipedia.org/wiki/Cyclic_redundancy_check. + /// FNV-1a hashing algorithm: http://www.isthe.com/chongo/tech/comp/fnv/#FNV-1a /// - internal class CRC32Hash + internal class FNV1a32Hash { - // CRC-32C polynomial representations - private const uint polynomial = 0x1EDC6F41; - private static uint[] table; + // FNV-1a algorithm parameters: http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param + private const uint FNV32_PRIME = 16777619; + private const uint FNV32_OFFSETBASIS = 2166136261; - static CRC32Hash() + internal static uint ComputeHash(byte[] buffer) { - uint temp = 0; - table = new uint[256]; - - for (int i = 0; i < table.Length; i++) - { - temp = (uint)i; - for (int j = 0; j < 8; j++) - { - if ((temp & 1) == 1) - { - temp = (temp >> 1) ^ polynomial; - } - else - { - temp >>= 1; - } - } - - table[i] = temp; - } - } - - private static uint Compute(byte[] buffer) - { - uint crc = 0xFFFFFFFF; - for (int i = 0; i < buffer.Length; ++i) + uint hash = FNV32_OFFSETBASIS; + for (int i = 0; i < buffer.Length; i++) { - var index = (byte)(crc ^ buffer[i] & 0xff); - crc = (crc >> 8) ^ table[index]; + hash = (hash ^ buffer[i]) * FNV32_PRIME; } - - return ~crc; - } - - internal static byte[] ComputeHash(byte[] buffer) - { - uint crcResult = Compute(buffer); - return BitConverter.GetBytes(crcResult); + return hash; } - internal static string ComputeHash(string input) + internal static uint ComputeHash(string input) { - byte[] hashBytes = ComputeHash(Encoding.UTF8.GetBytes(input)); - return BitConverter.ToString(hashBytes).Replace("-", string.Empty); + return ComputeHash(Encoding.UTF8.GetBytes(input)); } } @@ -241,7 +207,7 @@ private string GetHistorySaveFileMutexName() { // Return a reasonably unique name - it's not too important as there will rarely // be any contention. - return "PSReadLineHistoryFile_" + CRC32Hash.ComputeHash(_options.HistorySavePath); + return "PSReadLineHistoryFile_" + FNV1a32Hash.ComputeHash(_options.HistorySavePath); } private void IncrementalHistoryWrite() From 62265350dddd99aa91a4898e8f8d2de15c3e5975 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 23 Sep 2019 15:54:52 -0700 Subject: [PATCH 3/4] Address Jason's comments --- PSReadLine/Cmdlets.cs | 5 +---- PSReadLine/History.cs | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/PSReadLine/Cmdlets.cs b/PSReadLine/Cmdlets.cs index ee747b22..b2ff9de6 100644 --- a/PSReadLine/Cmdlets.cs +++ b/PSReadLine/Cmdlets.cs @@ -8,7 +8,6 @@ using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.IO; using System.Management.Automation; using System.Management.Automation.Language; using System.Reflection; @@ -648,9 +647,7 @@ public string HistorySavePath get => _historySavePath; set { - // Normalize the path - var altPathChar = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? '/' : '\\'; - _historySavePath = value?.Replace(altPathChar, Path.DirectorySeparatorChar); + _historySavePath = GetUnresolvedProviderPathFromPSPath(value); } } private string _historySavePath; diff --git a/PSReadLine/History.cs b/PSReadLine/History.cs index 75c2da7e..7c73c9b5 100644 --- a/PSReadLine/History.cs +++ b/PSReadLine/History.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Management.Automation; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -24,20 +25,20 @@ internal class FNV1a32Hash private const uint FNV32_PRIME = 16777619; private const uint FNV32_OFFSETBASIS = 2166136261; - internal static uint ComputeHash(byte[] buffer) + internal static uint ComputeHash(string input) { uint hash = FNV32_OFFSETBASIS; - for (int i = 0; i < buffer.Length; i++) + for (int i = 0; i < input.Length; i++) { - hash = (hash ^ buffer[i]) * FNV32_PRIME; + char c = input[i]; + uint lowByte = (uint)(c & 0x00FF); + hash = (hash ^ lowByte) * FNV32_PRIME; + + uint highByte = (uint)(c >> 8); + hash = (hash ^ highByte) * FNV32_PRIME; } return hash; } - - internal static uint ComputeHash(string input) - { - return ComputeHash(Encoding.UTF8.GetBytes(input)); - } } public partial class PSConsoleReadLine @@ -207,7 +208,12 @@ private string GetHistorySaveFileMutexName() { // Return a reasonably unique name - it's not too important as there will rarely // be any contention. - return "PSReadLineHistoryFile_" + FNV1a32Hash.ComputeHash(_options.HistorySavePath); + uint hashFromPath = FNV1a32Hash.ComputeHash( + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? _options.HistorySavePath.ToLower() + : _options.HistorySavePath); + + return "PSReadLineHistoryFile_" + hashFromPath.ToString(); } private void IncrementalHistoryWrite() From adfb0ae098810f6e270e163b162d35a07ed4cf15 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 23 Sep 2019 16:13:37 -0700 Subject: [PATCH 4/4] Move variable declaration out of loop --- PSReadLine/History.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/PSReadLine/History.cs b/PSReadLine/History.cs index 7c73c9b5..e53f36c4 100644 --- a/PSReadLine/History.cs +++ b/PSReadLine/History.cs @@ -27,16 +27,19 @@ internal class FNV1a32Hash internal static uint ComputeHash(string input) { - uint hash = FNV32_OFFSETBASIS; + char ch; + uint hash = FNV32_OFFSETBASIS, lowByte, highByte; + for (int i = 0; i < input.Length; i++) { - char c = input[i]; - uint lowByte = (uint)(c & 0x00FF); + ch = input[i]; + lowByte = (uint)(ch & 0x00FF); hash = (hash ^ lowByte) * FNV32_PRIME; - uint highByte = (uint)(c >> 8); + highByte = (uint)(ch >> 8); hash = (hash ^ highByte) * FNV32_PRIME; } + return hash; } }