Skip to content

Commit cbfd737

Browse files
athos-ribeiroGirgias
authored andcommitted
Fix off-by-one bug when truncating tempnam prefix
The tempnam documentation currently states that "Only the first 63 characters of the prefix are used, the rest are ignored". However when the prefix is 64 characters-long, the current implementation fails to strip the last character, diverging from the documented behavior. This patch fixes the implementation so it matches the documented behavior for that specific case where the prefix is 64 characters long. Closes GH-11870 Signed-off-by: George Peter Banyard <[email protected]>
1 parent 77252af commit cbfd737

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ PHP NEWS
4949

5050
- Standard:
5151
. Prevent int overflow on $decimals in number_format. (Marc Bennewitz)
52+
. Fixed bug GH-11870 (Fix off-by-one bug when truncating tempnam prefix)
53+
(athos-ribeiro)
5254

5355
03 Aug 2023, PHP 8.1.22
5456

ext/standard/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ PHP_FUNCTION(tempnam)
834834
ZEND_PARSE_PARAMETERS_END();
835835

836836
p = php_basename(prefix, prefix_len, NULL, 0);
837-
if (ZSTR_LEN(p) > 64) {
837+
if (ZSTR_LEN(p) >= 64) {
838838
ZSTR_VAL(p)[63] = '\0';
839839
}
840840

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
--TEST--
2+
Test tempnam() function: usage variations - test prefix maximum size
3+
--SKIPIF--
4+
<?php
5+
if (PHP_OS_FAMILY !== 'Windows') {
6+
die("skip Do not run on Windows");
7+
}
8+
?>
9+
--FILE--
10+
<?php
11+
/* Testing the maximum prefix size */
12+
13+
echo "*** Testing tempnam() maximum prefix size ***\n";
14+
$file_path = __DIR__."/tempnamVar9";
15+
mkdir($file_path);
16+
17+
$pre_prefix = "begin_";
18+
$post_prefix = "_end";
19+
$fixed_length = strlen($pre_prefix) + strlen($post_prefix);
20+
/* An array of prefixes */
21+
$names_arr = [
22+
$pre_prefix . str_repeat("x", 7) . $post_prefix,
23+
$pre_prefix . str_repeat("x", 63 - $fixed_length) . $post_prefix,
24+
$pre_prefix . str_repeat("x", 64 - $fixed_length) . $post_prefix,
25+
$pre_prefix . str_repeat("x", 65 - $fixed_length) . $post_prefix,
26+
$pre_prefix . str_repeat("x", 300) . $post_prefix,
27+
];
28+
29+
foreach($names_arr as $i=>$prefix) {
30+
echo "-- Iteration $i --\n";
31+
try {
32+
$file_name = tempnam("$file_path", $prefix);
33+
} catch (Error $e) {
34+
echo $e->getMessage(), "\n";
35+
continue;
36+
}
37+
38+
$base_name = basename($file_name);
39+
echo "File name is => ", $base_name, "\n";
40+
echo "File name length is => ", strlen($base_name), "\n";
41+
42+
if (file_exists($file_name)) {
43+
unlink($file_name);
44+
}
45+
}
46+
rmdir($file_path);
47+
48+
?>
49+
--CLEAN--
50+
<?php
51+
$file_path = __DIR__."/tempnamVar9";
52+
if (file_exists($file_path)) {
53+
array_map('unlink', glob($file_path . "/*"));
54+
rmdir($file_path);
55+
}
56+
?>
57+
--EXPECTF--
58+
*** Testing tempnam() maximum prefix size ***
59+
-- Iteration 0 --
60+
File name is => begin_%rx{7}%r_end%r.{6}%r
61+
File name length is => 23
62+
-- Iteration 1 --
63+
File name is => begin_%rx{53}%r_end%r.{6}%r
64+
File name length is => 69
65+
-- Iteration 2 --
66+
File name is => begin_%rx{54}%r_en%r.{6}%r
67+
File name length is => 69
68+
-- Iteration 3 --
69+
File name is => begin_%rx{55}%r_e%r.{6}%r
70+
File name length is => 69
71+
-- Iteration 4 --
72+
File name is => begin_%rx{57}%r%r.{6}%r
73+
File name length is => 69

0 commit comments

Comments
 (0)