Skip to content

Commit

Permalink
Fix possible collisions in ObjectId::create() when used inside a fork…
Browse files Browse the repository at this point in the history
…ed subprocess
  • Loading branch information
thekid committed Nov 28, 2024
1 parent 475c30a commit fea6da2
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 7 deletions.
7 changes: 7 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ MongoDB for XP Framework ChangeLog

## ?.?.? / ????-??-??

## 2.4.1 / 2024-11-27

* Fixed possible collisions in `ObjectId::create()` when used within a
forked subprocess by including the process ID in the random value's
calculation.
(@thekid)

## 2.4.0 / 2024-10-14

* Merged PR #48: Extend error handling to include if a write was retried
Expand Down
10 changes: 6 additions & 4 deletions src/main/php/com/mongodb/ObjectId.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

use lang\{Value, IllegalArgumentException};

/** @test com.mongodb.unittest.ObjectIdTest */
class ObjectId implements Value {
private static $rand, $counter;
private static $counter;
private static $rand= [];
private $string;

static function __static() {
self::$rand= random_bytes(5);
self::$counter= random_int(0, 4294967294); // uint32
}

Expand All @@ -29,7 +30,7 @@ public function __construct($string) {
* Creates a new random object ID consisting of:
*
* - a 4-byte timestamp value (uses current time if omitted)
* - a 5-byte random value
* - a 5-byte random value (per process)
* - a 3-byte incrementing counter, initialized to a random value
*
* @param ?int $timestamp
Expand All @@ -38,10 +39,11 @@ public function __construct($string) {
*/
public static function create($timestamp= null): self {
$uint32= self::$counter > 4294967294 ? self::$counter= 0 : ++self::$counter;
$pid= getmypid();
return new self(bin2hex(pack(
'Na5aaa',
null === $timestamp ? time() : $timestamp,
self::$rand,
self::$rand[$pid] ?? self::$rand[$pid]= random_bytes(5),
chr($uint32 >> 16),
chr($uint32 >> 8),
chr($uint32)
Expand Down
7 changes: 4 additions & 3 deletions src/test/php/com/mongodb/unittest/ObjectIdTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ public function create() {
}

#[Test]
public function create_generates_unique_ids() {
Assert::notEquals(ObjectId::create(), ObjectId::create());
public function create_with_same_timestamp_generates_unique_ids() {
$ts= time();
Assert::notEquals(ObjectId::create($ts), ObjectId::create($ts));
}

#[Test]
public function create_from_timestamp() {
public function create_from_timestamp_is_monotonic() {
$t= time();
$oid= ObjectId::create($t);
Assert::equals(dechex($t), substr($oid, 0, 8));
Expand Down

0 comments on commit fea6da2

Please sign in to comment.