Skip to content

Commit aed0fcc

Browse files
DmitryLukyanovrstam
authored andcommitted
CSHARP-4551: Avoid using PID when generating ObjectIds. (#1049)
1 parent 3a2a09d commit aed0fcc

File tree

2 files changed

+29
-63
lines changed

2 files changed

+29
-63
lines changed

src/MongoDB.Bson/ObjectModel/ObjectId.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
using System;
1717
using System.Diagnostics;
1818
using System.Runtime.CompilerServices;
19-
using System.Security;
2019
using System.Threading;
2120

2221
namespace MongoDB.Bson
@@ -385,17 +384,22 @@ public static void Unpack(byte[] bytes, out int timestamp, out int machine, out
385384
increment = (bytes[9] << 16) + (bytes[10] << 8) + bytes[11];
386385
}
387386

388-
// private static methods
389-
private static long CalculateRandomValue()
387+
// internal static methods
388+
internal static long CalculateRandomValue()
390389
{
390+
#if NET472_OR_GREATER
391391
var seed = (int)DateTime.UtcNow.Ticks ^ GetMachineHash() ^ GetPid();
392392
var random = new Random(seed);
393+
#else
394+
var random = new Random();
395+
#endif
393396
var high = random.Next();
394397
var low = random.Next();
395398
var combined = (long)((ulong)(uint)high << 32 | (ulong)(uint)low);
396399
return combined & 0xffffffffff; // low order 5 bytes
397400
}
398401

402+
// private static methods
399403
private static ObjectId Create(int timestamp, long random, int increment)
400404
{
401405
if (random < 0 || random > 0xffffffffff)
@@ -421,7 +425,8 @@ private static ObjectId Create(int timestamp, long random, int increment)
421425
[MethodImpl(MethodImplOptions.NoInlining)]
422426
private static int GetCurrentProcessId()
423427
{
424-
return Process.GetCurrentProcess().Id;
428+
using var process = Process.GetCurrentProcess();
429+
return process.Id;
425430
}
426431

427432
private static int GetMachineHash()
@@ -433,7 +438,14 @@ private static int GetMachineHash()
433438

434439
private static string GetMachineName()
435440
{
436-
return Environment.MachineName;
441+
try
442+
{
443+
return Environment.MachineName;
444+
}
445+
catch
446+
{
447+
return "";
448+
}
437449
}
438450

439451
private static short GetPid()
@@ -442,7 +454,7 @@ private static short GetPid()
442454
{
443455
return (short)GetCurrentProcessId(); // use low order two bytes only
444456
}
445-
catch (SecurityException)
457+
catch
446458
{
447459
return 0;
448460
}

src/MongoDB.Bson/Serialization/IdGenerators/AscendingGuidGenerator.cs

Lines changed: 11 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@
1414
*/
1515

1616
using System;
17-
using System.Diagnostics;
18-
using System.Runtime.CompilerServices;
19-
using System.Security;
20-
using System.Security.Cryptography;
21-
using System.Text;
2217
using System.Threading;
2318

2419
namespace MongoDB.Bson.Serialization.IdGenerators
@@ -30,40 +25,23 @@ namespace MongoDB.Bson.Serialization.IdGenerators
3025
/// as the storage representation.
3126
/// Internally the GUID is of the form
3227
/// 8 bytes: Ticks from DateTime.UtcNow.Ticks
33-
/// 3 bytes: hash of machine name
34-
/// 2 bytes: low order bytes of process Id
28+
/// 5 bytes: Random value from ObjectId spec
3529
/// 3 bytes: increment
3630
/// </summary>
3731
public class AscendingGuidGenerator : IIdGenerator
3832
{
3933
// private static fields
4034
private static readonly AscendingGuidGenerator __instance = new AscendingGuidGenerator();
41-
private static readonly byte[] __machineProcessId;
35+
private static readonly byte[] __random;
4236
private static int __increment;
4337

4438
// static constructor
4539
static AscendingGuidGenerator()
4640
{
47-
var machineHash = GetMachineHash();
48-
short processId;
49-
try
50-
{
51-
// use low order two bytes only
52-
processId = (short)GetCurrentProcessId();
53-
}
54-
catch (SecurityException)
55-
{
56-
processId = 0;
57-
}
58-
59-
__machineProcessId = new byte[5]
60-
{
61-
machineHash[0],
62-
machineHash[1],
63-
machineHash[2],
64-
(byte)(processId >> 8),
65-
(byte)(processId)
66-
};
41+
var random = ObjectId.CalculateRandomValue();
42+
var random8Bytes = BitConverter.GetBytes(random);
43+
__random = new byte[5];
44+
Array.Copy(random8Bytes, __random, 5); // the 5 bytes we need are the first 5 bytes assuming little-endian
6745
}
6846

6947
// public static properties
@@ -89,7 +67,7 @@ public static AscendingGuidGenerator Instance
8967
public object GenerateId(object container, object document)
9068
{
9169
var increment = Interlocked.Increment(ref __increment) & 0x00ffffff;
92-
return GenerateId(DateTime.UtcNow.Ticks, __machineProcessId, increment);
70+
return GenerateId(DateTime.UtcNow.Ticks, __random, increment);
9371
}
9472

9573
/// <summary>
@@ -109,11 +87,14 @@ public object GenerateId(
10987
byte[] machineProcessId,
11088
int increment)
11189
{
90+
if (machineProcessId == null) { throw new ArgumentNullException(nameof(machineProcessId)); }
91+
if (machineProcessId.Length != 5) { throw new ArgumentException($"{nameof(machineProcessId)} argument must be exactly 5 bytes", nameof(machineProcessId)); }
92+
var random5Bytes = machineProcessId; // changing the parameter name could be considered a breaking change
11293
var a = (int)(tickCount >> 32);
11394
var b = (short)(tickCount >> 16);
11495
var c = (short)(tickCount);
11596
var d = new byte[8];
116-
Array.Copy(machineProcessId, d, 5);
97+
Array.Copy(random5Bytes, d, 5);
11798
d[5] = (byte)(increment >> 16);
11899
d[6] = (byte)(increment >> 8);
119100
d[7] = (byte)(increment);
@@ -129,32 +110,5 @@ public bool IsEmpty(object id)
129110
{
130111
return id == null || (Guid)id == Guid.Empty;
131112
}
132-
133-
// private static methods
134-
/// <summary>
135-
/// Gets the current process id. This method exists because of how
136-
/// CAS operates on the call stack, checking for permissions before
137-
/// executing the method. Hence, if we inlined this call, the calling
138-
/// method would not execute before throwing an exception requiring the
139-
/// try/catch at an even higher level that we don't necessarily control.
140-
/// </summary>
141-
[MethodImpl(MethodImplOptions.NoInlining)]
142-
private static int GetCurrentProcessId()
143-
{
144-
return Process.GetCurrentProcess().Id;
145-
}
146-
147-
private static byte[] GetMachineHash()
148-
{
149-
// use instead of Dns.HostName so it will work offline
150-
var machineName = GetMachineName();
151-
var sha1 = SHA1.Create();
152-
return sha1.ComputeHash(Encoding.UTF8.GetBytes(machineName));
153-
}
154-
155-
private static string GetMachineName()
156-
{
157-
return Environment.MachineName;
158-
}
159113
}
160114
}

0 commit comments

Comments
 (0)