GNU/Linux >> Tutoriels Linux >  >> Linux

Comment contourner la limite Linux Too Many Arguments

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.


Linux
  1. Linux - Comment obtenir l'heure de l'horloge murale d'un processus en cours d'exécution ?

  2. Comment changer la limite de délai d'expiration de MySQL sous Linux ?

  3. Comment obtenir le nombre de CPU sous Linux en utilisant C ?

  4. Comment obtenir le nom d'utilisateur en C/C++ sous Linux ?

  5. Comment obtenir le nombre de disques physiques sous Linux ?

Comment limiter l'accès de l'utilisateur au système Linux

Comment limiter la profondeur de la liste récursive des fichiers sous Linux

Comment obtenir le nom de fichier à partir du chemin complet sous Linux

Comment obtenir le nombre de processeurs/cœurs sous Linux

Comment obtenir votre adresse IP sous Linux

Obtenir une adresse IP sous Linux :découvrez les nombreuses façons