modifier :
J'ai finalement pu passer <=256 Ko en tant qu'argument de ligne de commande unique (voir edit (4) dans le fond). Cependant, veuillez lire attentivement comment je l'ai fait et décidez par vous-même si c'est une voie que vous souhaitez suivre. Au moins, vous devriez être en mesure de comprendre pourquoi vous êtes "coincé" autrement d'après ce que j'ai découvert.
Avec le couplage de ARG_MAX
à ulim -s
/ 4 est venu l'introduction de MAX_ARG_STRLEN
au maximum longueur d'un argument :
/*
* 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
est défini comme 32 fois la taille de la page en 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
...
La taille de page par défaut est de 4 Ko, vous ne pouvez donc pas transmettre d'arguments de plus de 128 Ko.
Je ne peux pas l'essayer maintenant, mais peut-être que passer en mode page énorme (taille de page 4 Mo) si possible sur votre système résoudra ce problème.
Pour des informations et des références plus détaillées, consultez cette réponse à une question similaire sur Unix et Linux SE.
modifications :
(1) Selon cette réponse, on peut changer la taille de la page de x86_64
Linux à 1 Mo en activant CONFIG_TRANSPARENT_HUGEPAGE
et réglage CONFIG_TRANSPARENT_HUGEPAGE_MADVISE
à n
dans la configuration du noyau.
(2) Après avoir recompilé mon noyau avec les changements de configuration ci-dessus getconf PAGESIZE
renvoie toujours 4096.Selon cette réponse CONFIG_HUGETLB_PAGE
est également nécessaire que je pourrais récupérer via CONFIG_HUGETLBFS
. Je recompile maintenant et je testerai à nouveau.
(3) J'ai recompilé mon noyau avec CONFIG_HUGETLBFS
activé et maintenant /proc/meminfo
contient le HugePages_*
correspondant entrées mentionnées dans la section correspondante de la documentation du noyau. Cependant, la taille de la page selon getconf PAGESIZE
est toujours inchangé. Donc, alors que je devrais maintenant pouvoir demander d'énormes pages via mmap
appels, la taille de page par défaut du noyau déterminant MAX_ARG_STRLEN
est toujours fixé à 4 Ko.
(4) J'ai modifié linux/include/uapi/linux/binfmts.h
à #define MAX_ARG_STRLEN (PAGE_SIZE * 64)
, recompilé mon noyau et maintenant votre code produit :
...
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
Alors maintenant, la limite est passée de 128 Ko à 256 Ko comme prévu. Cependant, je ne connais pas les effets secondaires potentiels. Autant que je sache, mon système semble fonctionner correctement.
Mettez simplement les arguments dans un fichier et modifiez votre programme pour accepter les "arguments" d'un fichier. Une convention courante (notamment utilisée par GCC et plusieurs autres programmes GNU) est qu'un argument comme @/tmp/arglist.txt
demande à votre programme de lire les arguments du fichier /tmp/arglist.txt
, souvent une ligne par argument
Vous pourriez peut-être transmettre des données à travers de longues variables d'environnement, mais elles sont également limitées (et ce qui est limité par le noyau est en fait la taille de main
pile initiale de , contenant à la fois les arguments du programme et l'environnement)
Vous pouvez également modifier votre programme pour qu'il soit configurable via un fichier de configuration qui contiendrait les informations que vous souhaitez transmettre via des arguments.
D'une autre manière, il n'y a aucun moyen de contourner cette limitation (voir la page de manuel execve(2) et ses Limites sur la taille des arguments et de l'environnement section) - une fois que vous avez augmenté votre limite de pile (en utilisant setrlimit(2) avec RLIMIT_STACK
, généralement avec ulimit
intégré dans le shell parent). Vous devez vous en occuper autrement.