Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix off-by-one bug when truncating tempnam prefix #11870

Closed
wants to merge 2 commits into from

Conversation

athos-ribeiro
Copy link
Contributor

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.

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.
Copy link
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation should be fixed. Not the source code.

The source of truth is the code in php-src, the docs are meant to describe the behaviour of php-src not indicate how it should behave.

Indeed if this was the case dynamic properties for objects should have been removed with no RFC needed as this was undocumented until the deprecation came into effect.

@athos-ribeiro
Copy link
Contributor Author

Hi @Girgias, thanks for the review!

Still, I believe this is indeed a off-by-one bug with tempnam:

Check this out:

  $ php -r 'var_dump(tempnam(".", str_repeat("x", 63)));'
  string(78) "/tmp/foo/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9Ze3MZ"
  $ php -r 'var_dump(tempnam(".", str_repeat("x", 64)));'
  string(79) "/tmp/foo/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7Bt2mI"
  $ php -r 'var_dump(tempnam(".", str_repeat("x", 65)));'
  string(78) "/tmp/foo/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFN2yvX"

We currently allow the maximum prefix strlen to go all the way up to 64, but when a prefix greater than 64 is passed, we truncate it back to 63.

We could go the other way around and allow the strlen to go all the way up to 64 (and update the docs), but this would also require a code change.

FWIW, the bogus behavior was introduced in php 5.1.3 in 4ca3df5. Before that the value was copied from a char[64] array with strlcpy, i.e, the prefix would indeed be truncated after 63 characters.

However, I could not find the historical reasons behind the length limitation there.

Would you rather just document that "the prefix argument on tempnam length can be as large as 64 characters. If it is greater than that, then it will be truntcated to use only the first 63 characters"?

@Girgias
Copy link
Member

Girgias commented Aug 7, 2023

Hi @Girgias, thanks for the review!

Still, I believe this is indeed a off-by-one bug with tempnam:

Check this out:

  $ php -r 'var_dump(tempnam(".", str_repeat("x", 63)));'
  string(78) "/tmp/foo/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9Ze3MZ"
  $ php -r 'var_dump(tempnam(".", str_repeat("x", 64)));'
  string(79) "/tmp/foo/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7Bt2mI"
  $ php -r 'var_dump(tempnam(".", str_repeat("x", 65)));'
  string(78) "/tmp/foo/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFN2yvX"

We currently allow the maximum prefix strlen to go all the way up to 64, but when a prefix greater than 64 is passed, we truncate it back to 63.

We could go the other way around and allow the strlen to go all the way up to 64 (and update the docs), but this would also require a code change.

FWIW, the bogus behavior was introduced in php 5.1.3 in 4ca3df5. Before that the value was copied from a char[64] array with strlcpy, i.e, the prefix would indeed be truncated after 63 characters.

However, I could not find the historical reasons behind the length limitation there.

Would you rather just document that "the prefix argument on tempnam length can be as large as 64 characters. If it is greater than that, then it will be truntcated to use only the first 63 characters"?

Right... so it is more complicated than just a difference in documented behaviour.

So it seems this need to be fixed as shown, and possibly look if it makes sense to drop the length limit requirement for master

@athos-ribeiro
Copy link
Contributor Author

So it seems this need to be fixed as shown,
+1

and possibly look if it makes sense to drop the length limit requirement for master

I could not find the history behind that length. The git history only goes so far. I wonder if that is/was related to how temp files are created in specific systems. Then, I preferred to not touch the length atm.

}
rmdir($file_path);

?>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test should have a --CLEAN-- section removing the folder and all files within it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack. Added.

Comment on lines 28 to 48
for ($i=0; $i<count($names_arr); $i++) {
echo "-- Iteration $i --\n";
try {
$file_name = tempnam("$file_path", $names_arr[$i]);
} catch (Error $e) {
echo $e->getMessage(), "\n";
continue;
}

$base_name = basename($file_name);
echo "File name is => ";
print($base_name);
echo "\n";
echo "File name length is => ";
print(strlen($base_name));
echo "\n";

if (file_exists($file_name)) {
unlink($file_name);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use a foreach loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to keep consistency with the other tempnam test variations. I changed it to a foreach (maybe it improves readability).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those tests are probably very old and not written in the best way

Ensure the string is properly truncated when its length is greater than
63 characters.
@Girgias Girgias closed this in cbfd737 Aug 8, 2023
jorgsowa pushed a commit to jorgsowa/php-src that referenced this pull request Aug 16, 2023
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 phpGH-11870

Signed-off-by: George Peter Banyard <girgias@php.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants