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

Stop using PATH_MAX #744

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Tachi107
Copy link
Contributor

@Tachi107 Tachi107 commented Aug 6, 2022

PATH_MAX isn't guaranteed to be defined in Posix environments; it is only on systems that have a path length limit, and even in environments where it is defined its usage can lead to issues.

To avoid using PATH_MAX, I've made two main changes:

  • Where realpath() was used, I've changed the code to use its POSIX.1-2008's new behaviour, where passing a null pointer as the resolved_name buffer results in realpath() to automatically allocate a buffer large enough to handle the given path, that is returned to the caller. This has been supported for a long time as a GNU libc extension before being standardized.
  • Where readlink() was used, the size of the buffer was already determined when calling lstat(); the returned struct stat contains a st_size field, containing the number of bytes needed to store the symbolic link contents. This meant that to avoid using the tricky define I only needed to use a calloc()'d buffer instead of a static one, of size st_size + 1 as st_size doesn't account for the null terminator of C strings.

To make sure that memory is always freed, I've wrapped the new dynamic allocations in an std::unique_ptr with a deleter that calls free() on destruction.

To read more about why PATH_MAX leads to buggy code I'd suggest reading something like this: eklitzke.org/path-max-is-tricky

@Tachi107
Copy link
Contributor Author

This patch is currently being deployed in the howardhinnant-date Debian package, and allows tests to pass on 20 different architectures, including GNU Hurd which doesn't define PATH_MAX: https://buildd.debian.org/status/package.php?p=howardhinnant-date

@basilgello
Copy link

basilgello commented Oct 9, 2022

@Tachi107 wow, you packaged the libdate! Wonder how could I miss it!

I did package it in 2020 but I decided not to upload it because seemingly only Kodi used it.
Now I can safely switch to system package in sid/testing 👍

@Tachi107
Copy link
Contributor Author

Tachi107 commented Oct 9, 2022

@basilgello nice to hear! Please let me know if you find any issues with it :)

PATH_MAX isn't guaranteed to be defined in Posix environments; it is
only on systems that have a path length limit, and even in environments
where it is defined its usage can lead to issues.

To avoid using PATH_MAX, I've made two main changes:

- Where realpath() was used, I've changed the code to use its
  [POSIX.1-2008]'s new behaviour, where passing a null pointer as the
  resolved_name buffer results in realpath() to automatically allocate
  a buffer large enough to handle the given path, that is returned to
  the caller. This has been supported for a long time as a GNU libc
  extension before being standardized.
- Where readlink() was used, the size of the buffer was already
  determined when calling lstat(); the returned struct stat contains a
  st_size field, containing the number of bytes needed to store the
  symbolic link contents. This meant that to avoid using the tricky
  define I only needed to use a dynamically allocated buffer instead of
  a static one, of size stat.st_size (+1 when a null terminator is
  needed).

To make sure that memory is always freed, I've wrapped the new dynamic
allocations in an std::unique_ptr. The pointer returned by realpath()
must be freed with free(), so a unique_ptr with a custom deleter that
calls free() on destruction was used.

To read more about why PATH_MAX leads to buggy code I'd suggest reading
something like this: <https://eklitzke.org/path-max-is-tricky>.

[POSIX.1-2008]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html
@basilgello
Copy link

@Tachi107 Can you please upload the package to bullseye-bpo?

@Tachi107
Copy link
Contributor Author

I don't have the permission to do it yet, but while trying to check if doable I've discovered a small issue (see #754 (comment)). Once the issue is fixed and I'm allowed to backport packages, the package will be in bullseye-backports :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants