-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Expand file tree
/
Copy pathpdo_reconstruct_guard.phpt
More file actions
98 lines (92 loc) · 2.92 KB
/
Copy pathpdo_reconstruct_guard.phpt
File metadata and controls
98 lines (92 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
--TEST--
PDO::__construct() rejects reconstruction, reentrant construction and unsafe retry
--EXTENSIONS--
pdo_sqlite
--FILE--
<?php
$persistent = [PDO::ATTR_PERSISTENT => true];
// Sequential reconstruction of a constructed handle (plain and persistent).
$p = new PDO('sqlite::memory:');
try {
$p->__construct('sqlite::memory:');
} catch (\Error $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}
$q = new PDO('sqlite::memory:', null, null, $persistent);
try {
$q->__construct('sqlite::memory:', null, null, $persistent);
} catch (\Error $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}
// Reentrant construction: a uri: DSN opens a stream whose userland wrapper
// calls __construct() again on the same, still-constructing object.
class ReentWrapper
{
public $context;
private int $pos = 0;
private string $data = "sqlite::memory:";
public function stream_open($path, $mode, $options, &$opened): bool
{
global $obj;
try {
$obj->__construct('sqlite::memory:', null, null, [PDO::ATTR_PERSISTENT => true]);
} catch (\Error $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}
return true;
}
public function stream_read($count): string
{
$chunk = substr($this->data, $this->pos, $count);
$this->pos += strlen($chunk);
return $chunk;
}
public function stream_eof(): bool
{
return $this->pos >= strlen($this->data);
}
public function stream_stat()
{
return [];
}
}
stream_wrapper_register('reent', ReentWrapper::class);
$obj = (new ReflectionClass(PDO::class))->newInstanceWithoutConstructor();
$obj->__construct('uri:reent://x', null, null, $persistent);
// Retry after a failed persistent construct (which already swapped in the
// persistent handle before the driver factory failed).
$r = (new ReflectionClass(PDO::class))->newInstanceWithoutConstructor();
try {
$r->__construct('sqlite:/pdo-reconstruct-nonexistent/x.db', null, null, $persistent);
} catch (\Throwable $e) {
}
try {
$r->__construct('sqlite::memory:', null, null, $persistent);
} catch (\Error $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}
// Destructor reentry while a failed persistent connect() is unwinding.
class ReconstructOnDestruct extends Pdo\Sqlite
{
public function __destruct()
{
try {
$this->__construct('sqlite::memory:', null, null, [PDO::ATTR_PERSISTENT => true]);
} catch (\Error $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}
}
}
try {
ReconstructOnDestruct::connect('sqlite:/pdo-reconstruct-nonexistent/x.db', null, null, $persistent);
} catch (\Throwable $e) {
}
echo "done\n";
?>
--EXPECT--
Error: PDO object is already constructed
Error: PDO object is already constructed
Error: PDO object is already constructed
Error: PDO object is already constructed
Error: ReconstructOnDestruct object is already constructed
done