mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-06 11:57:10 +00:00
Unhackify Registry member cloning, fixes #3519
This commit is contained in:
parent
7aca41a530
commit
8ec2ba79de
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\utils\CloningRegistryTrait;
|
||||
use pocketmine\utils\RegistryTrait;
|
||||
use pocketmine\utils\Utils;
|
||||
use function assert;
|
||||
|
||||
/**
|
||||
@ -665,7 +665,7 @@ use function assert;
|
||||
* @method static Wool YELLOW_WOOL()
|
||||
*/
|
||||
final class VanillaBlocks{
|
||||
use RegistryTrait;
|
||||
use CloningRegistryTrait;
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
@ -678,14 +678,14 @@ final class VanillaBlocks{
|
||||
public static function fromString(string $name) : Block{
|
||||
$result = self::_registryFromString($name);
|
||||
assert($result instanceof Block);
|
||||
return clone $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block[]
|
||||
*/
|
||||
public static function getAll() : array{
|
||||
return Utils::cloneObjectArray(self::_registryGetAll());
|
||||
return self::_registryGetAll();
|
||||
}
|
||||
|
||||
protected static function setup() : void{
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\utils\CloningRegistryTrait;
|
||||
use pocketmine\utils\RegistryTrait;
|
||||
use pocketmine\utils\Utils;
|
||||
use function assert;
|
||||
|
||||
/**
|
||||
@ -292,7 +292,7 @@ use function assert;
|
||||
* @method static Skull ZOMBIE_HEAD()
|
||||
*/
|
||||
final class VanillaItems{
|
||||
use RegistryTrait;
|
||||
use CloningRegistryTrait;
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
@ -305,14 +305,14 @@ final class VanillaItems{
|
||||
public static function fromString(string $name) : Item{
|
||||
$result = self::_registryFromString($name);
|
||||
assert($result instanceof Item);
|
||||
return clone $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item[]
|
||||
*/
|
||||
public static function getAll() : array{
|
||||
return Utils::cloneObjectArray(self::_registryGetAll());
|
||||
return self::_registryGetAll();
|
||||
}
|
||||
|
||||
protected static function setup() : void{
|
||||
|
32
src/utils/CloningRegistryTrait.php
Normal file
32
src/utils/CloningRegistryTrait.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\utils;
|
||||
|
||||
trait CloningRegistryTrait{
|
||||
use RegistryTrait;
|
||||
|
||||
protected static function preprocessMember(object $member) : object{
|
||||
return clone $member;
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\utils;
|
||||
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function implode;
|
||||
@ -77,7 +78,11 @@ trait RegistryTrait{
|
||||
if(!isset(self::$members[$name])){
|
||||
throw new \InvalidArgumentException("No such registry member: " . self::class . "::" . $name);
|
||||
}
|
||||
return self::$members[$name];
|
||||
return self::preprocessMember(self::$members[$name]);
|
||||
}
|
||||
|
||||
protected static function preprocessMember(object $member) : object{
|
||||
return $member;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +108,9 @@ trait RegistryTrait{
|
||||
*/
|
||||
private static function _registryGetAll() : array{
|
||||
self::checkInit();
|
||||
return self::$members;
|
||||
return array_map(function(object $o) : object{
|
||||
return self::preprocessMember($o);
|
||||
}, self::$members);
|
||||
}
|
||||
|
||||
/**
|
||||
|
55
tests/phpunit/utils/CloningRegistryTraitTest.php
Normal file
55
tests/phpunit/utils/CloningRegistryTraitTest.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\utils;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
|
||||
final class CloningRegistryTraitTest extends TestCase{
|
||||
|
||||
/**
|
||||
* @phpstan-return \Generator<int, array{\Closure() : \stdClass}, void, void>
|
||||
*/
|
||||
public function cloningRegistryMembersProvider() : \Generator{
|
||||
yield [function() : \stdClass{ return TestCloningRegistry::TEST1(); }];
|
||||
yield [function() : \stdClass{ return TestCloningRegistry::TEST2(); }];
|
||||
yield [function() : \stdClass{ return TestCloningRegistry::TEST3(); }];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider cloningRegistryMembersProvider
|
||||
* @phpstan-param \Closure() : \stdClass $provider
|
||||
*/
|
||||
public function testEachMemberClone(\Closure $provider) : void{
|
||||
self::assertNotSame($provider(), $provider(), "Cloning registry should never return the same object twice");
|
||||
}
|
||||
|
||||
public function testGetAllClone() : void{
|
||||
$list1 = TestCloningRegistry::getAll();
|
||||
$list2 = TestCloningRegistry::getAll();
|
||||
foreach($list1 as $k => $member){
|
||||
self::assertNotSame($member, $list2[$k], "VanillaBlocks ought to clone its members");
|
||||
}
|
||||
}
|
||||
}
|
54
tests/phpunit/utils/TestCloningRegistry.php
Normal file
54
tests/phpunit/utils/TestCloningRegistry.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\utils;
|
||||
|
||||
/**
|
||||
* This doc-block is generated automatically, do not modify it manually.
|
||||
* This must be regenerated whenever registry members are added, removed or changed.
|
||||
* @see RegistryTrait::_generateMethodAnnotations()
|
||||
*
|
||||
* @method static \stdClass TEST1()
|
||||
* @method static \stdClass TEST2()
|
||||
* @method static \stdClass TEST3()
|
||||
*/
|
||||
final class TestCloningRegistry{
|
||||
use CloningRegistryTrait;
|
||||
|
||||
/**
|
||||
* @return \stdClass[]
|
||||
*/
|
||||
public static function getAll() : array{
|
||||
return self::_registryGetAll();
|
||||
}
|
||||
|
||||
public static function fromString(string $s) : \stdClass{
|
||||
return self::_registryFromString($s);
|
||||
}
|
||||
|
||||
protected static function setup() : void{
|
||||
self::_registryRegister("test1", new \stdClass());
|
||||
self::_registryRegister("test2", new \stdClass());
|
||||
self::_registryRegister("test3", new \stdClass());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user