GNU/Linux >> Belajar Linux >  >> Linux

Apa yang Mendefinisikan Ukuran Maksimum Untuk Argumen Perintah Tunggal?

Saya mendapat kesan bahwa panjang maksimum dari satu argumen bukanlah masalah di sini sebanyak ukuran total dari keseluruhan array argumen ditambah ukuran lingkungan, yang terbatas pada ARG_MAX . Jadi saya berpikir bahwa sesuatu seperti berikut ini akan berhasil:

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

Dengan - 100 menjadi lebih dari cukup untuk menjelaskan perbedaan antara ukuran lingkungan di shell dan echo proses. Sebaliknya saya mendapatkan kesalahan:

bash: /bin/echo: Argument list too long

Setelah bermain-main sebentar, saya menemukan bahwa maksimum adalah urutan besarnya hex penuh lebih kecil:

/bin/echo 
  $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) 
  >/dev/null

Ketika minus satu dihapus, kesalahan kembali. Tampaknya maksimum untuk satu argumen sebenarnya ARG_MAX/16 dan -1 memperhitungkan byte nol yang ditempatkan di akhir string dalam larik argumen.

Masalah lainnya adalah ketika argumen diulang, ukuran total array argumen bisa lebih dekat ke ARG_MAX , tapi masih belum cukup:

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

Menggunakan "${args[0]:6533}" di sini membuat argumen terakhir 1 byte lebih panjang dan memberikan Argument list too long kesalahan. Perbedaan ini tidak mungkin diperhitungkan dengan ukuran lingkungan yang diberikan:

$ cat /proc/$$/environ | wc -c
1045

Pertanyaan:

  1. Apakah ini perilaku yang benar, atau ada bug di suatu tempat?
  2. Jika tidak, apakah perilaku ini didokumentasikan di mana saja? Apakah ada parameter lain yang mendefinisikan maksimum untuk satu argumen?
  3. Apakah perilaku ini terbatas pada Linux (atau bahkan versi tertentu)?
  4. Apa yang menyebabkan perbedaan ~5KB tambahan antara ukuran maksimum sebenarnya dari larik argumen ditambah perkiraan ukuran lingkungan dan ARG_MAX ?

Info tambahan:

uname -a
Linux graeme-rock 3.13-1-amd64 #1 SMP Debian 3.13.5-1 (2014-03-04) x86_64 GNU/Linux

Jawaban yang Diterima:

Jawaban

  1. Jelas bukan bug.
  2. Parameter yang menentukan ukuran maksimum untuk satu argumen adalah MAX_ARG_STRLEN . Tidak ada dokumentasi untuk parameter ini selain komentar di 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
    

    Seperti yang ditunjukkan, Linux juga memiliki batas (sangat besar) pada jumlah argumen untuk suatu perintah.

  3. Batas ukuran argumen tunggal (yang berbeda dari batasan keseluruhan argumen plus lingkungan) tampaknya khusus untuk Linux. Artikel ini memberikan perbandingan detail ARG_MAX dan yang setara pada sistem mirip Unix. MAX_ARG_STRLEN dibahas untuk Linux, tetapi tidak disebutkan padanan apa pun di sistem lain mana pun.

    Artikel di atas juga menyatakan bahwa MAX_ARG_STRLEN diperkenalkan di Linux 2.6.23, bersama dengan sejumlah perubahan lain yang berkaitan dengan maksimum argumen perintah (dibahas di bawah). Log/diff untuk komit dapat ditemukan di sini.

  4. Masih belum jelas apa yang menyebabkan perbedaan tambahan antara hasil getconf ARG_MAX dan ukuran maksimum yang sebenarnya dari argumen ditambah lingkungan. Jawaban terkait Stephane Chazelas, menunjukkan bahwa bagian dari ruang diperhitungkan oleh pointer ke masing-masing string argumen/lingkungan. Namun, penyelidikan saya sendiri menunjukkan bahwa pointer ini tidak dibuat di awal execve panggilan sistem ketika mungkin masih mengembalikan E2BIG kesalahan pada proses pemanggilan (walaupun pointer ke setiap argv string pasti dibuat nanti).

    Juga, string bersebelahan dalam memori sejauh yang saya bisa lihat, jadi tidak ada celah memori karena melakukan penyelarasan di sini. Meskipun sangat mungkin menjadi faktor dalam apa pun tidak menghabiskan memori ekstra. Memahami apa yang menggunakan ruang ekstra membutuhkan pengetahuan yang lebih rinci tentang bagaimana kernel mengalokasikan memori (yang merupakan pengetahuan yang berguna untuk dimiliki, jadi saya akan menyelidiki dan memperbaruinya nanti).

Terkait:Apa perbedaan antara titik koma dan ampersand ganda &&?

Kebingungan ARG_MAX

Sejak Linux 2.6.23 (sebagai hasil dari commit ini), telah terjadi perubahan pada cara penanganan maksimum argumen perintah yang membuat Linux berbeda dari sistem mirip Unix lainnya. Selain menambahkan MAX_ARG_STRLEN dan MAX_ARG_STRINGS , hasil dari getconf ARG_MAX sekarang tergantung pada ukuran tumpukan dan mungkin berbeda dari ARG_MAX di limits.h .

Biasanya hasil getconf ARG_MAX akan menjadi 1/4 dari ukuran tumpukan. Pertimbangkan yang berikut ini di bash menggunakan ulimit untuk mendapatkan ukuran tumpukan:

$ echo $(( $(ulimit -s)*1024 / 4 ))  # ulimit output in KiB
2097152
$ getconf ARG_MAX
2097152

Namun, perilaku di atas sedikit diubah oleh komit ini (ditambahkan di Linux 2.6.25-rc4~121). ARG_MAX di limits.h sekarang berfungsi sebagai batas bawah yang keras pada hasil getconf ARG_MAX . Jika ukuran tumpukan diatur sedemikian rupa sehingga 1/4 ukuran tumpukan kurang dari ARG_MAX di limits.h , lalu limits.h nilai yang akan digunakan:

$ 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

Perhatikan juga bahwa jika ukuran tumpukan ditetapkan lebih rendah dari ARG_MAX minimum yang memungkinkan , lalu ukuran tumpukan (RLIMIT_STACK ) menjadi batas atas ukuran argumen/lingkungan sebelum E2BIG dikembalikan (walaupun getconf ARG_MAX akan tetap menampilkan nilai di limits.h ).

Hal terakhir yang perlu diperhatikan adalah jika kernel dibuat tanpa CONFIG_MMU (dukungan untuk perangkat keras manajemen memori), kemudian pemeriksaan ARG_MAX dinonaktifkan, sehingga batas tidak berlaku. Meskipun MAX_ARG_STRLEN dan MAX_ARG_STRINGS masih berlaku.

Bacaan Lebih Lanjut

  • Jawaban terkait oleh Stephane Chazelas – https://unix.stackexchange.com/a/110301/48083
  • Dalam halaman terperinci yang mencakup sebagian besar hal di atas. Termasuk tabel ARG_MAX (dan setara) nilai pada sistem mirip Unix lainnya – http://www.in-ulm.de/~mascheck/various/argmax/
  • Sepertinya pengenalan MAX_ARG_STRLEN menyebabkan bug pada Automake yang menyematkan skrip shell ke Makefile menggunakan sh -c – http://www.mail-archive.com/[email protected]/msg05522.html

Linux
  1. Apa yang setara dengan perintah updatedb Linux untuk Mac?

  2. Apa yang setara dengan perintah File Linux untuk windows?

  3. Apa unit ukuran default di linux ls -l perintah

  1. Untuk apa Linux test -a command test?

  2. Mengubah PATH, sekarang saya mendapatkan perintah tidak ditemukan untuk semuanya

  3. Apa yang dimaksud dengan 'bidang' untuk perintah potong?

  1. 8 tips untuk baris perintah Linux

  2. Bagaimana cara menemukan ukuran tumpukan maksimum?

  3. Apa gunanya opsi -o dalam perintah useradd?