Open
Description
Symfony version(s) affected
7.0.0
Description
This bug is very rare. But with an increase in the number of processes and concurrency in general, it ceases to be potential. The main problem is that the storage response about deleting a value from it is not checked. Instead, an additional query is made that only checks for the existence of the key, not its contents (although this is not used at all, but could be used to store a unique value that would uniquely identify the process that acquired the lock).
How to reproduce
Following the code from documentation:
$lock = $factory->createLock('pdf-creation', ttl: 30);
if (!$lock->acquire()) {
return;
}
$lock->release(); // <------ This may erroneously result in an exception by design
Possible Solution
- We can check the result of
$this->storage->delete
call (we have to make different implementations) - Store unique value as an uniquely identify the process that acquired the lock/
Additional Context
To understand
https://github.com/symfony/lock/blob/7.0/Lock.php:217
try {
$this->store->delete($this->key);
$this->dirty = false;
} catch (LockReleasingException $e) {
throw $e;
} catch (\Exception $e) {
throw new LockReleasingException(sprintf('Failed to release the "%s" lock.', $this->key), 0, $e);
}
//////////////////////////////////////////
// If another process acquires the lock at this point, the next line will return true and throw an exception.
//////////////////////////////////////////
if ($this->store->exists($this->key)) {
throw new LockReleasingException(sprintf('Failed to release the "%s" lock, the resource is still locked.', $this->key));
}