Navigation Menu

Skip to content

Commit

Permalink
fix(entity): prevent deadloops during recursive entity delete
Browse files Browse the repository at this point in the history
fixes #10836
  • Loading branch information
jeabakker committed Apr 11, 2022
1 parent aace3ce commit 139998f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 0 deletions.
14 changes: 14 additions & 0 deletions engine/classes/Elgg/Database/EntityTable.php
Expand Up @@ -82,6 +82,11 @@ class EntityTable {
* @var Translator
*/
protected $translator;

/**
* @var int[]
*/
protected $deleted_guids = [];

/**
* Constructor
Expand Down Expand Up @@ -561,6 +566,9 @@ public function delete(\ElggEntity $entity, $recursive = true) {
$entity->ban();
}

// we're going to delete this entity, log the guid to prevent deadloops
$this->deleted_guids[] = $entity->guid;

if ($recursive) {
$this->deleteRelatedEntities($entity);
}
Expand Down Expand Up @@ -606,6 +614,12 @@ protected function deleteRelatedEntities(\ElggEntity $entity) {
]);
/* @var $e \ElggEntity */
foreach ($batch as $e) {
if (in_array($e->guid, $this->deleted_guids)) {
// prevent deadloops, doing this here in case of large deletes which could cause query length issues
$batch->reportFailure();
continue;
}

if (!$this->delete($e, true)) {
$batch->reportFailure();
}
Expand Down
Expand Up @@ -696,4 +696,38 @@ public function emptyValues() {
];
}

public function testDeleteDeadloopPrevented() {
$user = $this->getAdmin();

$session = elgg_get_session();
$session->setLoggedInUser($user);

$object1 = $this->createObject([
'owner_guid' => $user->guid,
]);
$object2 = $this->createObject([
'owner_guid' => $user->guid,
'container_guid' => $object1->guid,
]);
$object3 = $this->createObject([
'owner_guid' => $user->guid,
'container_guid' => $object2->guid,
]);

$object1->container_guid = $object3->guid;
$object1->save();

$called_guids = [];
$testing_event = $this->registerTestingEvent('delete:before', 'object', function(\Elgg\Event $event) use (&$called_guids) {
$object = $event->getObject();
$this->assertNotContains($object->guid, $called_guids, 'Deadloop detected during entity delete');

$called_guids[] = $object->guid;
});

$object1->delete();

$testing_event->assertNumberOfCalls(3);
$testing_event->unregister();
}
}

0 comments on commit 139998f

Please sign in to comment.