GNU/Linux >> Znalost Linux >  >> Linux

Co definuje maximální velikost pro jeden příkazový argument?

Měl jsem dojem, že maximální délka jednoho argumentu zde není problémem ani tak jako celková velikost celkového pole argumentů plus velikost prostředí, které je omezeno na ARG_MAX . Tak jsem si myslel, že něco jako následující by uspělo:

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

S - 100 je více než dostačující k zohlednění rozdílu mezi velikostí prostředí v shellu a echo proces. Místo toho se mi zobrazila chyba:

bash: /bin/echo: Argument list too long

Po chvíli hraní jsem zjistil, že maximum bylo o celý hex řádově menší:

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

Po odstranění mínus jedna se chyba vrátí. Zdánlivě maximum pro jeden argument je ve skutečnosti ARG_MAX/16 a -1 odpovídá za nulový bajt umístěný na konci řetězce v poli argumentů.

Dalším problémem je, že když se argument opakuje, celková velikost pole argumentů se může blížit ARG_MAX , ale stále to není úplně ono:

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

Pomocí "${args[0]:6533}" zde je poslední argument o 1 bajt delší a Argument list too long chyba. Tento rozdíl pravděpodobně nebude způsoben velikostí daného prostředí:

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

Otázky:

  1. Je toto chování správné, nebo je někde chyba?
  2. Pokud ne, je toto chování někde zdokumentováno? Existuje jiný parametr, který definuje maximum pro jeden argument?
  3. Je toto chování omezeno na Linux (nebo dokonce jeho konkrétní verze)?
  4. Co je příčinou dalších ~5KB nesrovnalostí mezi skutečnou maximální velikostí pole argumentů plus přibližná velikost prostředí a ARG_MAX ?

Další informace:

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

Přijatá odpověď:

Odpovědi

  1. Určitě to není chyba.
  2. Parametr, který definuje maximální velikost pro jeden argument, je MAX_ARG_STRLEN . Pro tento parametr neexistuje žádná jiná dokumentace než komentáře v 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
    

    Jak je ukázáno, Linux má také (velmi velký) limit na počet argumentů příkazu.

  3. Zdá se, že omezení velikosti jednoho argumentu (které se liší od celkového limitu argumentů plus prostředí) je specifické pro Linux. Tento článek poskytuje podrobné srovnání ARG_MAX a ekvivalenty na systémech podobných Unixu. MAX_ARG_STRLEN je diskutován pro Linux, ale není zde žádná zmínka o ekvivalentu na jiných systémech.

    Výše uvedený článek také uvádí, že MAX_ARG_STRLEN byl představen v Linuxu 2.6.23 spolu s řadou dalších změn týkajících se maxima argumentů příkazů (probráno níže). Log/diff pro odevzdání lze nalézt zde.

  4. Stále není jasné, čím je způsoben další nesoulad mezi výsledkem getconf ARG_MAX a skutečná maximální možná velikost argumentů plus prostředí. Související odpověď Stephana Chazelase naznačuje, že část prostoru připadá na ukazatele na každý z řetězců argumentů/prostředí. Moje vlastní šetření však naznačuje, že tyto ukazatele nejsou vytvořeny na začátku execve systémové volání, kdy může stále vracet E2BIG chyba volajícího procesu (ačkoliv ukazatele na každý argv řetězec se jistě vytvoří později).

    Řetězce jsou také v paměti souvislé, pokud vidím, takže zde neprovádějte žádné mezery v paměti. I když je velmi pravděpodobné, že bude faktorem v tom, co dělá využít další paměť. Pochopení toho, co využívá extra prostor, vyžaduje podrobnější znalosti o tom, jak jádro alokuje paměť (což jsou užitečné znalosti, takže to prozkoumám a aktualizuji později).

Související:Jaký je rozdíl mezi středníkem a dvojitým a&&?

ARG_MAX zmatek

Od Linuxu 2.6.23 (v důsledku tohoto odevzdání) došlo ke změnám ve způsobu, jakým jsou zpracovávány maxima argumentů příkazů, díky čemuž se Linux liší od jiných systémů podobných Unixu. Kromě přidání MAX_ARG_STRLEN a MAX_ARG_STRINGS , výsledek getconf ARG_MAX nyní závisí na velikosti zásobníku a může se lišit od ARG_MAX v limits.h .

Obvykle výsledek getconf ARG_MAX bude 1/4 velikosti zásobníku. Zvažte následující v bash pomocí ulimit získat velikost zásobníku:

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

Výše uvedené chování však bylo mírně změněno tímto potvrzením (přidáno v Linuxu 2.6.25-rc4~121). ARG_MAX v limits.h nyní slouží jako pevná spodní hranice výsledku getconf ARG_MAX . Pokud je velikost zásobníku nastavena tak, že 1/4 velikost zásobníku je menší než ARG_MAX v limits.h a poté limits.h bude použita hodnota:

$ 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

Všimněte si také, že pokud je velikost zásobníku nastavena nižší než minimální možné ARG_MAX , pak velikost zásobníku (RLIMIT_STACK ) se stane horním limitem velikosti argumentu/prostředí před E2BIG je vráceno (ačkoli getconf ARG_MAX bude stále zobrazovat hodnotu v limits.h ).

Poslední věc, kterou je třeba poznamenat, je, že pokud je jádro sestaveno bez CONFIG_MMU (podpora hardwaru pro správu paměti), poté kontrola ARG_MAX je zakázáno, takže limit neplatí. Ačkoli MAX_ARG_STRLEN a MAX_ARG_STRINGS stále platí.

Další čtení

  • Související odpověď od Stephana Chazelase – https://unix.stackexchange.com/a/110301/48083
  • Na podrobné stránce pokrývající většinu výše uvedeného. Zahrnuje tabulku ARG_MAX (a ekvivalentní) hodnoty na jiných unixových systémech – http://www.in-ulm.de/~mascheck/various/argmax/
  • Zdá se, že zavedení MAX_ARG_STRLEN způsobil chybu v Automake, která vkládala skripty shellu do Makefiles pomocí sh -c – http://www.mail-archive.com/[email protected]/msg05522.html

Linux
  1. 8 tipů pro příkazový řádek Linuxu

  2. Jaká je maximální velikost hodnoty proměnné prostředí Linux?

  3. Jak zjistím maximální velikost zásobníku?

  1. Jaká je výchozí jednotka velikosti v příkazu linux ls -l

  2. Změněna PATH, nyní dostávám příkaz nenalezen pro všechno

  3. Jaký je účel cd ` (backtick)?

  1. Jaký je smysl příkazu hostnamectl?

  2. Jaké je maximální číslo portu?

  3. Jak určit nejlepší velikost bajtu pro příkaz dd