Skip to content

Commit bd2010f

Browse files
authored
Merge pull request #162 from php-java/enhance-jvm-operation-safety
To enhance JVM operations safety
2 parents 2c45eda + 2d610e7 commit bd2010f

8 files changed

Lines changed: 116 additions & 20 deletions

File tree

src/Core/JVM/ConstantPool.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use PHPJava\Core\Stream\Reader\ReaderInterface;
55
use PHPJava\Exceptions\ReadEntryException;
66
use PHPJava\Exceptions\ReadOnlyException;
7+
use PHPJava\Exceptions\RuntimeException;
78
use PHPJava\Kernel\Maps\ConstantPoolTag;
89
use PHPJava\Kernel\Structures\_Class;
910
use PHPJava\Kernel\Structures\_Double;
@@ -112,6 +113,11 @@ public function offsetGet($offset)
112113
if ($this->entries[$offset] instanceof FreezableInterface) {
113114
$this->entries[$offset]->freeze();
114115
}
116+
if (!array_key_exists($offset, $this->entries)) {
117+
throw new RuntimeException(
118+
'Cannot refer an entry on the Constant Pool (index: ' . $offset . ')'
119+
);
120+
}
115121
return $this->entries[$offset];
116122
}
117123

src/Core/JVM/Invoker/Invokable.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use PHPJava\Kernel\Types\_Double;
2424
use PHPJava\Kernel\Types\_Long;
2525
use PHPJava\Packages\java\lang\NoSuchMethodException;
26+
use PHPJava\Packages\java\lang\UnsupportedOperationException;
2627
use PHPJava\Utilities\AttributionResolver;
2728
use PHPJava\Utilities\DebugTool;
2829
use PHPJava\Utilities\Formatter;
@@ -213,6 +214,17 @@ function ($argument) {
213214
$pointer = $reader->getOffset() - 1;
214215

215216
$fullName = '\\PHPJava\\Kernel\\Mnemonics\\' . $mnemonic;
217+
218+
if (!class_exists($fullName)) {
219+
throw new UnsupportedOperationException(
220+
sprintf(
221+
'%s(0x%02X) operation does not supported.',
222+
ltrim($mnemonic, '_'),
223+
$opcode
224+
)
225+
);
226+
}
227+
216228
if ($isEnabledTrace) {
217229
$debugTraces['executed'][] = [$opcode, $mnemonic, $localStorage, $stacks, $pointer];
218230
$debugTraces['mnemonic_indexes'][] = $pointer;

src/Kernel/Mnemonics/_invokevirtual.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
use PHPJava\Exceptions\UnableToCatchException;
66
use PHPJava\Kernel\Attributes\CodeAttribute;
77
use PHPJava\Kernel\Structures\_ExceptionTable;
8+
use PHPJava\Kernel\Types\Type;
89
use PHPJava\Utilities\AttributionResolver;
910
use PHPJava\Utilities\Formatter;
1011
use PHPJava\Utilities\Normalizer;
12+
use PHPJava\Utilities\TypeResolver;
1113

1214
final class _invokevirtual implements OperationInterface
1315
{
@@ -105,7 +107,16 @@ public function execute(): void
105107
}
106108

107109
if ($signature[0]['type'] !== 'void') {
108-
$this->pushToOperandStack($result);
110+
/**
111+
* @var Type $typeClass
112+
*/
113+
[$type, $typeClass] = TypeResolver::getType($signature[0]);
114+
115+
$this->pushToOperandStack(
116+
$type === TypeResolver::IS_PRIMITIVE
117+
? $typeClass::get($result)
118+
: $result
119+
);
109120
}
110121
}
111122
}

src/Kernel/Mnemonics/_ldc2_w.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use PHPJava\Kernel\Types\_Double;
55
use PHPJava\Kernel\Types\_Long;
6+
use PHPJava\Packages\java\lang\UnsupportedOperationException;
67

78
final class _ldc2_w implements OperationInterface
89
{
@@ -13,12 +14,14 @@ public function execute(): void
1314
{
1415
$cpInfo = $this->getConstantPool();
1516
$data = $cpInfo[$this->readUnsignedShort()];
16-
1717
$value = null;
18+
1819
if (($data instanceof \PHPJava\Kernel\Structures\_Long)) {
1920
$value = _Long::get($data->getBytes());
2021
} elseif ($data instanceof \PHPJava\Kernel\Structures\_Double) {
2122
$value = _Double::get($data->getBytes());
23+
} else {
24+
throw new UnsupportedOperationException('Unsupported operation.');
2225
}
2326

2427
$this->pushToOperandStack($value);

src/Kernel/Types/Type.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ public function __construct($value)
2020
);
2121
}
2222

23-
$this->value = ($value instanceof self)
24-
? $value->getValue()
25-
: static::filter($value);
23+
$this->value = static::filter(
24+
($value instanceof self)
25+
? $value->getValue()
26+
: $value
27+
);
2628
}
2729

2830
public function __debugInfo()
@@ -40,8 +42,15 @@ public function __debugInfo()
4042
public static function get($value)
4143
{
4244
static $instantiated = null;
43-
$identity = (string) $value;
44-
return $instantiated[$identity] = $instantiated[$identity] ?? new static($identity);
45+
if (is_object($value)) {
46+
if ($value instanceof static) {
47+
return $value;
48+
}
49+
$identity = spl_object_hash($value);
50+
} else {
51+
$identity = (string) $value;
52+
}
53+
return $instantiated[$identity] = $instantiated[$identity] ?? new static($value);
4554
}
4655

4756
public function getValue()
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
namespace PHPJava\Packages\java\lang;
3+
4+
// use PHPJava\Packages\java\io\Serializable;
5+
6+
/**
7+
* @parent \PHPJava\Packages\java\lang\_Object
8+
* @parent \PHPJava\Packages\java\lang\Throwable
9+
* @parent \PHPJava\Packages\java\lang\Exception
10+
* @parent \PHPJava\Packages\java\lang\RuntimeException
11+
*/
12+
class UnsupportedOperationException extends RuntimeException // implements Serializable
13+
{
14+
}

src/Utilities/Extractor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static function realValue($value)
2020
public static function getRealValue($value)
2121
{
2222
if ($value instanceof Type) {
23-
return $value->getValue();
23+
return TypeResolver::extractPrimitiveValueFromType($value);
2424
}
2525
return $value;
2626
}

src/Utilities/TypeResolver.php

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
class TypeResolver
2222
{
23+
const IS_CLASS = 'class';
24+
const IS_PRIMITIVE = 'primitive';
25+
2326
const PHP_TYPE_MAP = [
2427
'integer' => 'I',
2528
'float' => 'F',
@@ -63,12 +66,10 @@ class TypeResolver
6366
const PHP_SCALAR_MAP = [
6467
// [ TypeClass, Instantiation ]
6568
'string' => [_String::class, true],
66-
'float' => [_Float::class, true],
67-
'double' => [_Float::class, true],
68-
'int' => [_Int::class, true],
69-
'integer' => [_Int::class, true],
70-
'bool' => [_Boolean::class, true],
71-
'boolean' => [_Boolean::class, true],
69+
'float' => [_Float::class, false],
70+
'double' => [_Float::class, false],
71+
'integer' => [_Int::class, false],
72+
'boolean' => [_Boolean::class, false],
7273
];
7374

7475
const PHP_TO_JAVA_MAP = [
@@ -82,7 +83,7 @@ class TypeResolver
8283
* @param $signature
8384
* @throws TypeException
8485
*/
85-
public static function getMappedSignatureType($signature): string
86+
public static function getMappedSignatureType(string $signature): string
8687
{
8788
if (isset(static::SIGNATURE_MAP[$signature])) {
8889
return static::SIGNATURE_MAP[$signature];
@@ -93,7 +94,7 @@ public static function getMappedSignatureType($signature): string
9394
/**
9495
* @param $type
9596
*/
96-
public static function resolve($type): string
97+
public static function resolve(string $type): string
9798
{
9899
$flipped = array_flip(static::SIGNATURE_MAP);
99100
if (isset($flipped[$type])) {
@@ -106,6 +107,47 @@ public static function resolve($type): string
106107
return 'L' . $type;
107108
}
108109

110+
public static function extractPrimitiveValueFromType(Type $value)
111+
{
112+
$extractedValue = (string) $value->getValue();
113+
if ($value instanceof _Int || $value instanceof _Long) {
114+
return (int) $extractedValue;
115+
}
116+
if ($value instanceof _Float || $value instanceof _Double) {
117+
return (float) $extractedValue;
118+
}
119+
if ($value instanceof _Boolean) {
120+
return $extractedValue === 'true' ? true : false;
121+
}
122+
123+
return $extractedValue;
124+
}
125+
126+
/**
127+
* @param array $signatureArray a formatted signature array
128+
* @throws TypeException
129+
* @return string
130+
*/
131+
public static function getType(array $signatureArray)
132+
{
133+
$type = $signatureArray['type'];
134+
if ($type === 'class') {
135+
$className = Runtime::PHP_PACKAGES_DIRECTORY . '\\' . str_replace('/', '\\', $signatureArray['class_name']);
136+
return [
137+
static::IS_CLASS,
138+
$className,
139+
];
140+
}
141+
$result = static::TYPES_MAP[strtolower($type)] ?? null;
142+
if ($result === null) {
143+
throw new TypeException('Unknown type: ' . $type);
144+
}
145+
return [
146+
static::IS_PRIMITIVE,
147+
$result,
148+
];
149+
}
150+
109151
/**
110152
* @param $value
111153
* @return bool|mixed|string
@@ -123,17 +165,16 @@ public static function resolveFromPHPType($value)
123165
/**
124166
* @param $type
125167
*/
126-
public static function convertJavaTypeSimplyForPHP($type): string
168+
public static function convertJavaTypeSimplyForPHP(string $type): string
127169
{
128170
return static::AMBIGUOUS_TYPES_ON_PHP[$type] ?? $type;
129171
}
130172

131173
/**
132174
* @param $arguments
133-
* @param string $defaultJavaArgumentType
134175
* @throws TypeException
135176
*/
136-
public static function convertPHPtoJava($arguments, $defaultJavaArgumentType = 'java.lang.String'): array
177+
public static function convertPHPtoJava($arguments, string $defaultJavaArgumentType = 'java.lang.String'): array
137178
{
138179
$phpType = gettype($arguments);
139180
$deepArray = 0;
@@ -245,7 +286,7 @@ public static function compare(string $a, string $b): bool
245286
* @throws TypeException
246287
* @throws \ReflectionException
247288
*/
248-
public static function getExtendedClasses($class): array
289+
public static function getExtendedClasses(string $class): array
249290
{
250291
static $loadedExtendedRoots = [];
251292
$result = [];

0 commit comments

Comments
 (0)