File name too long causing failure to open temporary head file in dlltool

Message ID 20240813014001.4134320-1-jiaying.song.cn@windriver.com
State New
Headers
Series File name too long causing failure to open temporary head file in dlltool |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Song, Jiaying (CN) Aug. 13, 2024, 1:40 a.m. UTC
  From: Jiaying Song <jiaying.song.cn@windriver.com>

During the execution of the command: i686-w64-mingw32-dlltool
--input-def $def_filepath --output-delaylib $filepath --dllname qemu.exe
An error occurred:
i686-w64-mingw32-dlltool: failed to open temporary head file: ..._w64_mingw32_nativesdk_qemu_8_2_2_build_plugins_libqemu_plugin_api_a_h.s

Due to the path length exceeding the Linux system's file name length
limit (NAME_MAX=255), the temporary file name generated by the
i686-w64-mingw32-dlltool command becomes too long to open. To address
this, a new temporary file name prefix is generated using tmp_prefix =
prefix_encode ("d", getpid()), ensuring that the file name does not
exceed the system's length limit.

Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com>
---
 binutils/dlltool.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)
  

Comments

Martin Storsjö Aug. 13, 2024, 8:44 a.m. UTC | #1
On Tue, 13 Aug 2024, jiaying.song.cn@windriver.com wrote:

> From: Jiaying Song <jiaying.song.cn@windriver.com>
>
> During the execution of the command: i686-w64-mingw32-dlltool
> --input-def $def_filepath --output-delaylib $filepath --dllname qemu.exe
> An error occurred:
> i686-w64-mingw32-dlltool: failed to open temporary head file: ..._w64_mingw32_nativesdk_qemu_8_2_2_build_plugins_libqemu_plugin_api_a_h.s
>
> Due to the path length exceeding the Linux system's file name length
> limit (NAME_MAX=255), the temporary file name generated by the
> i686-w64-mingw32-dlltool command becomes too long to open. To address
> this, a new temporary file name prefix is generated using tmp_prefix =
> prefix_encode ("d", getpid()), ensuring that the file name does not
> exceed the system's length limit.
>
> Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com>
> ---
> binutils/dlltool.c | 17 ++++++++++++-----
> 1 file changed, 12 insertions(+), 5 deletions(-)
>
> diff --git a/binutils/dlltool.c b/binutils/dlltool.c
> index 066c99a4..acaeb5a7 100644
> --- a/binutils/dlltool.c
> +++ b/binutils/dlltool.c
> @@ -4099,11 +4099,18 @@ main (int ac, char **av)
>       if (imp_name || delayimp_name)
>         {
>           const char *input = imp_name ? imp_name : delayimp_name;
> -          tmp_prefix = xmalloc (strlen (input) + 2);
> -          sprintf (tmp_prefix, "%s_", input);
> -          for (i = 0; tmp_prefix[i]; i++)
> -            if (!ISALNUM (tmp_prefix[i]))
> -              tmp_prefix[i] = '_';
> +          if ((strlen(input) + 2) > NAME_MAX)
> +            {
> +              tmp_prefix = prefix_encode ("d", getpid ());
> +            }
> +          else
> +            {
> +              tmp_prefix = xmalloc (strlen (input) + 2);
> +              sprintf (tmp_prefix, "%s_", input);
> +              for (i = 0; tmp_prefix[i]; i++)
> +              if (!ISALNUM (tmp_prefix[i]))
> +                tmp_prefix[i] = '_';
> +            }

Thanks for keeping the existing codepath when possible.

Using getpid() here as fallback isn't great, we used to use getpid() 
before c4a8df19ba0a82aa8dea88d9f72ed9e63cb1fa84, but moved away from it. 
(The commit message of that commit is unnecessarily terse - see 
https://sourceware.org/pipermail/binutils/2022-January/119111.html for the 
original commit message.)

Using it as fallback when the normal case is too long shouldn't affect 
those who use it currently with manageable file names - but I wonder if we 
could come up with an even better solution?

To expand on the context here - there are a number of constraints on the 
temp prefix used here. In particular - the temp prefix that is used ends 
up in archive member names within the output library.

- For multiple dlltool invocations running in the same directory in 
parallel, the temp prefix needs to be unique, to avoid temp files 
clashing. Using getpid() does achieve this.

- It would be desireable if the temp prefix is deterministic.

- For two separate libraries with different names, the temp prefix also 
should be unique. (Import libraries are frequently merged into larger 
umbrella libraries. In this case, if two of the input libraries use the 
same temp prefix, the merged library doesn't work as it should.)


It is tempting to only use the file name of the output, rather than the 
full (relative) path - but that causes clashes if we have two dlltool 
processes in parallel, in the same directory, building 
"lib32/libkernel32.a" and "lib64/libkernel32.a". (This exact case was 
fixed in d65c0ddddd85645cab6f11fd711d21638a74489f, see 
https://sourceware.org/pipermail/binutils/2022-March/119999.html and 
https://sourceware.org/bugzilla/show_bug.cgi?id=28885 for references 
around that.)


For this particular case, I wonder if it'd be best to take the last 
(NAME_MAX - 20) chars of the output name, rather than the full string? 
That would retain determinism, and it should hopefully keep the most 
unique parts of the identifier?

Other than that, I don't have a strong objection to falling back on 
getpid(), as long as the existing codepath is used primarily.

// Martin
  

Patch

diff --git a/binutils/dlltool.c b/binutils/dlltool.c
index 066c99a4..acaeb5a7 100644
--- a/binutils/dlltool.c
+++ b/binutils/dlltool.c
@@ -4099,11 +4099,18 @@  main (int ac, char **av)
       if (imp_name || delayimp_name)
         {
           const char *input = imp_name ? imp_name : delayimp_name;
-          tmp_prefix = xmalloc (strlen (input) + 2);
-          sprintf (tmp_prefix, "%s_", input);
-          for (i = 0; tmp_prefix[i]; i++)
-            if (!ISALNUM (tmp_prefix[i]))
-              tmp_prefix[i] = '_';
+          if ((strlen(input) + 2) > NAME_MAX)
+            {
+              tmp_prefix = prefix_encode ("d", getpid ());
+            }
+          else
+            {
+              tmp_prefix = xmalloc (strlen (input) + 2);
+              sprintf (tmp_prefix, "%s_", input);
+              for (i = 0; tmp_prefix[i]; i++)
+              if (!ISALNUM (tmp_prefix[i]))
+                tmp_prefix[i] = '_';
+            }
         }
       else
         {