ここでは、引数配列全体の合計サイズに、ARG_MAXに制限されている環境のサイズを加えたものほど、単一の引数の最大長は問題ではないという印象を受けました。 。したがって、私は次のようなものが成功すると思いました:
env_size=$(cat /proc/$$/environ | wc -c)
(( arg_size = $(getconf ARG_MAX) - $env_size - 100 ))
/bin/echo $(tr -dc [:alnum:] </dev/urandom | head -c $arg_size) >/dev/null
- 100を使用 シェル内の環境のサイズとechoの違いを説明するには十分すぎるほどです 処理する。代わりに、エラーが発生しました:
bash: /bin/echo: Argument list too long
しばらく遊んだ後、最大値が16進数で1桁小さいことがわかりました:
/bin/echo
$(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1)))
>/dev/null
マイナス1を削除すると、エラーが返されます。単一の引数の最大値は、実際にはARG_MAX/16のようです。 および-1 引数配列の文字列の最後に配置されたヌルバイトを考慮します。
もう1つの問題は、引数が繰り返されると、引数配列の合計サイズがARG_MAXに近くなる可能性があることです。 、しかしまだ完全ではありません:
args=( $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) )
for x in {1..14}; do
args+=( ${args[0]} )
done
/bin/echo "${args[@]}" "${args[0]:6534}" >/dev/null
"${args[0]:6533}"を使用する ここでは、最後の引数が1バイト長くなり、Argument list too long エラー。この違いは、与えられた環境のサイズによって説明される可能性は低いです:
$ cat /proc/$$/environ | wc -c
1045
質問:
- これは正しい動作ですか、それともどこかにバグがありますか?
- そうでない場合、この動作はどこかに文書化されていますか?単一の引数の最大値を定義する別のパラメーターはありますか?
- この動作はLinux(またはそのような特定のバージョン)に限定されていますか?
- 引数配列の実際の最大サイズに環境のおおよそのサイズを加えたものと
ARG_MAXの間の追加の最大5KBの不一致の原因は何ですか ?
追加情報:
uname -a
Linux graeme-rock 3.13-1-amd64 #1 SMP Debian 3.13.5-1 (2014-03-04) x86_64 GNU/Linux
承認された回答:
回答
- 間違いなくバグではありません。
-
1つの引数の最大サイズを定義するパラメーターは
MAX_ARG_STRLENです。 。binfmts.hのコメント以外に、このパラメータのドキュメントはありません。 :/* * These are the maximum length and maximum number of strings passed to the * execve() system call. MAX_ARG_STRLEN is essentially random but serves to * prevent the kernel from being unduly impacted by misaddressed pointers. * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer. */ #define MAX_ARG_STRLEN (PAGE_SIZE * 32) #define MAX_ARG_STRINGS 0x7FFFFFFF示されているように、Linuxにはコマンドへの引数の数にも(非常に大きな)制限があります。
-
単一の引数のサイズの制限(引数と環境の全体的な制限とは異なります)は、Linuxに固有のようです。この記事では、
ARG_MAXの詳細な比較について説明します。 およびUnixライクなシステムでの同等のもの。MAX_ARG_STRLENLinuxについては説明されていますが、他のシステムで同等のものについては言及されていません。上記の記事には、
MAX_ARG_STRLENも記載されています。 Linux 2.6.23で導入され、コマンド引数の最大値に関連する他の多くの変更が加えられました(以下で説明します)。コミットのログ/差分はここにあります。 -
getconf ARG_MAXの結果間の追加の不一致の原因はまだ明らかではありません。 引数と環境の実際の最大可能サイズ。 Stephane Chazelasの関連する回答は、スペースの一部が各引数/環境文字列へのポインタによって占められていることを示唆しています。ただし、私自身の調査によると、これらのポインタはexecveの初期には作成されていません。 それでもE2BIGを返す可能性がある場合のシステムコール 呼び出しプロセスへのエラー(ただし、各argvへのポインター 文字列は確かに後で作成されます。また、文字列は私が見る限りメモリ内で連続しているので、ここで整列することによるメモリギャップはありません。何をするにしてもの要因になる可能性が非常に高いですが 余分なメモリを使い果たします。余分なスペースを使用するものを理解するには、カーネルがメモリを割り当てる方法についてのより詳細な知識が必要です(これは有用な知識なので、後で調査して更新します)。
ARG_MAXの混乱
Linux 2.6.23以降(このコミットの結果)、コマンド引数の最大値の処理方法が変更され、Linuxは他のUnixライクなシステムとは異なります。 MAX_ARG_STRLENの追加に加えて およびMAX_ARG_STRINGS 、getconf ARG_MAXの結果 現在はスタックサイズに依存し、ARG_MAXとは異なる場合があります limits.hで 。
通常、getconf ARG_MAXの結果 1/4になります スタックサイズの。 bashで次のことを考慮してください ulimitを使用する スタックサイズを取得するには:
$ echo $(( $(ulimit -s)*1024 / 4 )) # ulimit output in KiB
2097152
$ getconf ARG_MAX
2097152
ただし、上記の動作はこのコミットによってわずかに変更されました(Linux 2.6.25-rc4〜121で追加されました)。 ARG_MAX limits.hで getconf ARG_MAXの結果の厳しい下限として機能するようになりました 。スタックサイズが1/4のように設定されている場合 スタックサイズのARG_MAX未満 limits.hで 、次にlimits.h 使用される値:
$ grep ARG_MAX /usr/include/linux/limits.h
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
$ ulimit -s 256
$ echo $(( $(ulimit -s)*1024 / 4 ))
65536
$ getconf ARG_MAX
131072
スタックサイズが可能な最小のARG_MAXよりも低く設定されている場合にも注意してください 、次にスタックのサイズ(RLIMIT_STACK )E2BIGの前の引数/環境サイズの上限になります が返されます(ただし、getconf ARG_MAX 引き続きlimits.hに値が表示されます 。
最後に注意すべきことは、カーネルがCONFIG_MMUなしで構築されている場合です。 (メモリ管理ハードウェアのサポート)、次にARG_MAXのチェック が無効になっているため、制限は適用されません。 MAX_ARG_STRLEN およびMAX_ARG_STRINGS 引き続き適用します。
参考資料
- Stephane Chazelasによる関連回答– https://unix.stackexchange.com/a/110301/48083
- 上記のほとんどをカバーする詳細ページ。
ARG_MAXのテーブルが含まれています (および同等の)他のUnixライクなシステムの値– http://www.in-ulm.de/~mascheck/various/argmax/ -
MAX_ARG_STRLENの導入のようですsh -cを使用してシェルスクリプトをMakefileに埋め込むAutomakeでバグが発生しました – http://www.mail-archive.com/ [email protected] /msg05522.html