Skip to content

Commit 9bae9ab

Browse files
Girgiasm-vo
andauthored
Fix GH-8861: correctly handle string lengths in SplFileinfo methods (#8869)
* Fix GH-8861: correctly handle string lengths in \SplFileinfo::getBasename Co-authored-by: M. Vondano <m-vo@users.noreply.github.com>
1 parent 63c7418 commit 9bae9ab

File tree

5 files changed

+263
-6
lines changed

5 files changed

+263
-6
lines changed

ext/spl/spl_directory.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -651,14 +651,17 @@ static inline HashTable *spl_filesystem_object_get_debug_info(zend_object *objec
651651
pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "fileName", sizeof("fileName")-1);
652652
path = spl_filesystem_object_get_path(intern);
653653

654-
if (ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
654+
if (path && ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
655+
/* +1 to skip the trailing / of the path in the file name */
655656
ZVAL_STRINGL(&tmp, ZSTR_VAL(intern->file_name) + ZSTR_LEN(path) + 1, ZSTR_LEN(intern->file_name) - (ZSTR_LEN(path) + 1));
656657
} else {
657658
ZVAL_STR_COPY(&tmp, intern->file_name);
658659
}
659660
zend_symtable_update(rv, pnstr, &tmp);
660661
zend_string_release_ex(pnstr, /* persistent */ false);
661-
zend_string_release_ex(path, /* persistent */ false);
662+
if (path) {
663+
zend_string_release_ex(path, /* persistent */ false);
664+
}
662665
}
663666
if (intern->type == SPL_FS_DIR) {
664667
#ifdef HAVE_GLOB
@@ -920,9 +923,11 @@ PHP_METHOD(SplFileInfo, getFilename)
920923

921924
path = spl_filesystem_object_get_path(intern);
922925

923-
if (path && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
924-
size_t path_len = ZSTR_LEN(path);
925-
RETVAL_STRINGL(ZSTR_VAL(intern->file_name) + path_len + 1, ZSTR_LEN(intern->file_name) - (path_len + 1));
926+
ZEND_ASSERT(path);
927+
if (path && ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
928+
/* +1 to skip the trailing / of the path in the file name */
929+
size_t path_len = ZSTR_LEN(path) + 1;
930+
RETVAL_STRINGL(ZSTR_VAL(intern->file_name) + path_len, ZSTR_LEN(intern->file_name) - path_len);
926931
} else {
927932
RETVAL_STR_COPY(intern->file_name);
928933
}
@@ -1037,7 +1042,8 @@ PHP_METHOD(SplFileInfo, getBasename)
10371042

10381043
path = spl_filesystem_object_get_path(intern);
10391044

1040-
if (path && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
1045+
if (path && ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
1046+
/* +1 to skip the trailing / of the path in the file name */
10411047
fname = ZSTR_VAL(intern->file_name) + ZSTR_LEN(path) + 1;
10421048
flen = ZSTR_LEN(intern->file_name) - (ZSTR_LEN(path) + 1);
10431049
} else {
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
--TEST--
2+
Check Glob iterator is okay with SplFileInfo getPath method calls
3+
--FILE--
4+
<?php
5+
6+
$o = new GlobIterator(__DIR__.'/*.abcdefghij');
7+
8+
echo "Test getATime()\n";
9+
var_dump($o->getATime());
10+
echo "Test getBasename()\n";
11+
var_dump($o->getBasename());
12+
echo "Test getCTime()\n";
13+
var_dump($o->getCTime());
14+
echo "Test getExtension()\n";
15+
var_dump($o->getExtension());
16+
echo "Test getFilename()\n";
17+
var_dump($o->getFilename());
18+
echo "Test getGroup()\n";
19+
var_dump($o->getGroup());
20+
echo "Test getInode()\n";
21+
var_dump($o->getInode());
22+
echo "Test getMTime()\n";
23+
var_dump($o->getMTime());
24+
echo "Test getOwner()\n";
25+
var_dump($o->getOwner());
26+
echo "Test getPath()\n";
27+
var_dump($o->getPath());
28+
echo "Test getPathInfo()\n";
29+
var_dump($o->getPathInfo());
30+
echo "Test getPathname()\n";
31+
var_dump($o->getPathname());
32+
echo "Test getPerms()\n";
33+
var_dump($o->getPerms());
34+
echo "Test getRealPath()\n";
35+
var_dump($o->getRealPath());
36+
echo "Test getSize()\n";
37+
var_dump($o->getSize());
38+
echo "Test getType()\n";
39+
var_dump($o->getType());
40+
echo "Test isDir()\n";
41+
var_dump($o->isDir());
42+
echo "Test isExecutable()\n";
43+
var_dump($o->isExecutable());
44+
echo "Test isFile()\n";
45+
var_dump($o->isFile());
46+
echo "Test isLink()\n";
47+
var_dump($o->isLink());
48+
echo "Test isReadable()\n";
49+
var_dump($o->isReadable());
50+
echo "Test isWritable()\n";
51+
var_dump($o->isWritable());
52+
echo "Test __toString()\n";
53+
var_dump($o->__toString());
54+
echo "Test __debugInfo()\n";
55+
var_dump($o);
56+
57+
?>
58+
--EXPECTF--
59+
Test getATime()
60+
bool(false)
61+
Test getBasename()
62+
string(0) ""
63+
Test getCTime()
64+
bool(false)
65+
Test getExtension()
66+
string(0) ""
67+
Test getFilename()
68+
string(0) ""
69+
Test getGroup()
70+
bool(false)
71+
Test getInode()
72+
bool(false)
73+
Test getMTime()
74+
bool(false)
75+
Test getOwner()
76+
bool(false)
77+
Test getPath()
78+
string(0) ""
79+
Test getPathInfo()
80+
NULL
81+
Test getPathname()
82+
string(0) ""
83+
Test getPerms()
84+
bool(false)
85+
Test getRealPath()
86+
string(%d) "%s"
87+
Test getSize()
88+
bool(false)
89+
Test getType()
90+
bool(false)
91+
Test isDir()
92+
bool(false)
93+
Test isExecutable()
94+
bool(false)
95+
Test isFile()
96+
bool(false)
97+
Test isLink()
98+
bool(false)
99+
Test isReadable()
100+
bool(false)
101+
Test isWritable()
102+
bool(false)
103+
Test __toString()
104+
string(0) ""
105+
Test __debugInfo()
106+
object(GlobIterator)#1 (4) {
107+
["pathName":"SplFileInfo":private]=>
108+
string(0) ""
109+
["fileName":"SplFileInfo":private]=>
110+
string(0) ""
111+
["glob":"DirectoryIterator":private]=>
112+
string(%d) "glob://%s"
113+
["subPathName":"RecursiveDirectoryIterator":private]=>
114+
string(0) ""
115+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
--TEST--
2+
SPL: SplFileInfo::_debugInfo() basic test
3+
--FILE--
4+
<?php
5+
// without $suffix
6+
var_dump(new \SplFileInfo('/path/to/a.txt'));
7+
var_dump(new \SplFileInfo('path/to/b'));
8+
var_dump(new \SplFileInfo('c.txt'));
9+
var_dump(new \SplFileInfo('d'));
10+
var_dump(new \SplFileInfo('~/path/to//e'));
11+
12+
// with $suffix
13+
var_dump(new \SplFileInfo('path/to/a.txt'));
14+
var_dump(new \SplFileInfo('path/to/bbb.txt'));
15+
var_dump(new \SplFileInfo('path/to/ccc.txt'));
16+
var_dump(new \SplFileInfo('d.txt'));
17+
var_dump(new \SplFileInfo('e.txt'));
18+
var_dump(new \SplFileInfo('f'));
19+
?>
20+
--EXPECT--
21+
object(SplFileInfo)#1 (2) {
22+
["pathName":"SplFileInfo":private]=>
23+
string(14) "/path/to/a.txt"
24+
["fileName":"SplFileInfo":private]=>
25+
string(5) "a.txt"
26+
}
27+
object(SplFileInfo)#1 (2) {
28+
["pathName":"SplFileInfo":private]=>
29+
string(9) "path/to/b"
30+
["fileName":"SplFileInfo":private]=>
31+
string(1) "b"
32+
}
33+
object(SplFileInfo)#1 (2) {
34+
["pathName":"SplFileInfo":private]=>
35+
string(5) "c.txt"
36+
["fileName":"SplFileInfo":private]=>
37+
string(5) "c.txt"
38+
}
39+
object(SplFileInfo)#1 (2) {
40+
["pathName":"SplFileInfo":private]=>
41+
string(1) "d"
42+
["fileName":"SplFileInfo":private]=>
43+
string(1) "d"
44+
}
45+
object(SplFileInfo)#1 (2) {
46+
["pathName":"SplFileInfo":private]=>
47+
string(12) "~/path/to//e"
48+
["fileName":"SplFileInfo":private]=>
49+
string(1) "e"
50+
}
51+
object(SplFileInfo)#1 (2) {
52+
["pathName":"SplFileInfo":private]=>
53+
string(13) "path/to/a.txt"
54+
["fileName":"SplFileInfo":private]=>
55+
string(5) "a.txt"
56+
}
57+
object(SplFileInfo)#1 (2) {
58+
["pathName":"SplFileInfo":private]=>
59+
string(15) "path/to/bbb.txt"
60+
["fileName":"SplFileInfo":private]=>
61+
string(7) "bbb.txt"
62+
}
63+
object(SplFileInfo)#1 (2) {
64+
["pathName":"SplFileInfo":private]=>
65+
string(15) "path/to/ccc.txt"
66+
["fileName":"SplFileInfo":private]=>
67+
string(7) "ccc.txt"
68+
}
69+
object(SplFileInfo)#1 (2) {
70+
["pathName":"SplFileInfo":private]=>
71+
string(5) "d.txt"
72+
["fileName":"SplFileInfo":private]=>
73+
string(5) "d.txt"
74+
}
75+
object(SplFileInfo)#1 (2) {
76+
["pathName":"SplFileInfo":private]=>
77+
string(5) "e.txt"
78+
["fileName":"SplFileInfo":private]=>
79+
string(5) "e.txt"
80+
}
81+
object(SplFileInfo)#1 (2) {
82+
["pathName":"SplFileInfo":private]=>
83+
string(1) "f"
84+
["fileName":"SplFileInfo":private]=>
85+
string(1) "f"
86+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
SPL: SplFileInfo::getBasename() basic test
3+
--FILE--
4+
<?php
5+
// without $suffix
6+
echo (new \SplFileInfo('/path/to/a.txt'))->getBasename() . PHP_EOL;
7+
echo (new \SplFileInfo('path/to/b'))->getBasename() . PHP_EOL;
8+
echo (new \SplFileInfo('c.txt'))->getBasename() . PHP_EOL;
9+
echo (new \SplFileInfo('d'))->getBasename() . PHP_EOL;
10+
echo (new \SplFileInfo('~/path/to//e'))->getBasename() . PHP_EOL . PHP_EOL;
11+
12+
// with $suffix
13+
echo (new \SplFileInfo('path/to/a.txt'))->getBasename('.txt') . PHP_EOL;
14+
echo (new \SplFileInfo('path/to/bbb.txt'))->getBasename('b.txt') . PHP_EOL;
15+
echo (new \SplFileInfo('path/to/ccc.txt'))->getBasename('to/ccc.txt') . PHP_EOL;
16+
echo (new \SplFileInfo('d.txt'))->getBasename('txt') . PHP_EOL;
17+
echo (new \SplFileInfo('e.txt'))->getBasename('e.txt') . PHP_EOL;
18+
echo (new \SplFileInfo('f'))->getBasename('.txt');
19+
?>
20+
--EXPECT--
21+
a.txt
22+
b
23+
c.txt
24+
d
25+
e
26+
27+
a
28+
bb
29+
ccc.txt
30+
d.
31+
e.txt
32+
f
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
SPL: SplFileInfo::getFilename() basic test
3+
--FILE--
4+
<?php
5+
6+
echo (new \SplFileInfo('/path/to/a.txt'))->getFilename() . PHP_EOL;
7+
echo (new \SplFileInfo('path/to/b'))->getFilename() . PHP_EOL;
8+
echo (new \SplFileInfo('c.txt'))->getFilename() . PHP_EOL;
9+
echo (new \SplFileInfo('d'))->getFilename() . PHP_EOL;
10+
echo (new \SplFileInfo('~/path/to//e'))->getFilename() . PHP_EOL . PHP_EOL;
11+
12+
?>
13+
--EXPECT--
14+
a.txt
15+
b
16+
c.txt
17+
d
18+
e

0 commit comments

Comments
 (0)