upravit:
Konečně se mi podařilo předat <=256 kB jako jediný argument příkazového řádku (viz úprava (4) ve spodní části). Přečtěte si prosím pozorně, jak jsem to udělal, a sami se rozhodněte, zda je to cesta, kterou se chcete vydat. Přinejmenším byste měli být schopni pochopit, proč jste „zaseknutý“ jinak z toho, co jsem zjistil.
Se spojením ARG_MAX
do ulim -s
/ 4 přišlo zavedení MAX_ARG_STRLEN
jako max. délka argumentu:
/*
* linux/fs/exec.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
...
#ifdef CONFIG_MMU
/*
* The nascent bprm->mm is not visible until exec_mmap() but it can
* use a lot of memory, account these pages in current->mm temporary
* for oom_badness()->get_mm_rss(). Once exec succeeds or fails, we
* change the counter back via acct_arg_size(0).
*/
...
static bool valid_arg_len(struct linux_binprm *bprm, long len)
{
return len <= MAX_ARG_STRLEN;
}
...
#else
...
static bool valid_arg_len(struct linux_binprm *bprm, long len)
{
return len <= bprm->p;
}
#endif /* CONFIG_MMU */
...
static int copy_strings(int argc, struct user_arg_ptr argv,
struct linux_binprm *bprm)
{
...
str = get_user_arg_ptr(argv, argc);
...
len = strnlen_user(str, MAX_ARG_STRLEN);
if (!len)
goto out;
ret = -E2BIG;
if (!valid_arg_len(bprm, len))
goto out;
...
}
...
MAX_ARG_STRLEN
je definována jako 32násobek velikosti stránky v linux/include/uapi/linux/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
...
Výchozí velikost stránky je 4 KB, takže nemůžete předávat argumenty delší než 128 KB.
Teď to nemohu vyzkoušet, ale možná tento problém vyřeší přepnutí do režimu velké stránky (velikost stránky 4 MB), pokud je to možné ve vašem systému.
Podrobnější informace a odkazy naleznete v této odpovědi na podobnou otázku na Unix &Linux SE.
úpravy:
(1) Podle této odpovědi lze změnit velikost stránky x86_64
Linux na 1 MB povolením CONFIG_TRANSPARENT_HUGEPAGE
a nastavení CONFIG_TRANSPARENT_HUGEPAGE_MADVISE
na n
v konfiguraci jádra.
(2) Po rekompilaci mého jádra s výše uvedenými změnami konfigurace getconf PAGESIZE
stále vrací 4096. Podle této odpovědi CONFIG_HUGETLB_PAGE
je také potřeba, kterou bych mohl stáhnout přes CONFIG_HUGETLBFS
. Nyní provádím rekompilaci a znovu otestuji.
(3) Překompiloval jsem své jádro s CONFIG_HUGETLBFS
povoleno a nyní /proc/meminfo
obsahuje odpovídající HugePages_*
položky uvedené v odpovídající části dokumentace jádra. Nicméně velikost stránky podle getconf PAGESIZE
je stále beze změny. Takže i když bych nyní měl být schopen požadovat velké stránky prostřednictvím mmap
volání, výchozí velikost stránky jádra určuje MAX_ARG_STRLEN
je stále fixní na 4 kB.
(4) Upravil jsem linux/include/uapi/linux/binfmts.h
na #define MAX_ARG_STRLEN (PAGE_SIZE * 64)
, překompiloval mé jádro a váš kód nyní vytváří:
...
117037
123196
123196
129680
129680
136505
143689
151251
159211
...
227982
227982
239981
239981
252611
252611
265906
./testCL: line 11: ./foo: Argument list too long
279901
./testCL: line 11: ./foo: Argument list too long
294632
./testCL: line 11: ./foo: Argument list too long
Nyní se tedy limit posunul ze 128 kB na 256 kB, jak se očekávalo. Nevím však o potenciálních vedlejších účincích. Pokud mohu soudit, zdá se, že můj systém běží v pořádku.
Jednoduše vložte argumenty do nějakého souboru a upravte svůj program tak, aby akceptoval "argumenty" ze souboru. Běžnou konvencí (používá se zejména GCC a několika dalšími programy GNU) je, že argument jako @/tmp/arglist.txt
požádá váš program, aby přečetl argumenty ze souboru /tmp/arglist.txt
, často jeden řádek na argument
Možná můžete předávat některá data přes dlouhé proměnné prostředí, ale ty jsou také omezené (a co je omezeno jádrem ve skutečnosti je velikost main
počáteční zásobník 's, obsahující argumenty programu i prostředí)
Případně upravte svůj program tak, aby byl konfigurovatelný pomocí nějakého konfiguračního souboru, který by obsahoval informace, které chcete předat argumenty.
Jinými způsoby neexistuje způsob, jak toto omezení obejít (viz manuálová stránka execve(2) a její Omezení velikosti argumentů a prostředí sekce) - jakmile zvýšíte limit zásobníku (pomocí setrlimit(2) s RLIMIT_STACK
, obvykle s ulimit
vestavěný v nadřazeném shellu). Musíte se s tím vypořádat jinak.