Heirloom Toolchest tr: erreur (s) essayant de supprimer le complément d'un set contenant un caractère multi-octets?

J'essaie d'utiliser la command tr du Heirloom Toolchest pour surmonter une limitation actuelle de l'implémentation de coreutils afin de pouvoir "pomper" (avec les options -dc ) des caractères multi-octets d'un générateur "random" ( / dev / urandom ) au terminal. Il est à noter que cela a été compilé à partir de la source sur Archbang après avoir échoué à le faire en utilisant la (les) version (s) AUR.

Pour simplifier cela, choisissons un caractère (☠) et calculons sa valeur octale car c'est ainsi qu'il doit être exprimé pour le file toolchest tr :

 echo '☠' | hexdump -b # -b for octal 0000000 342 230 240 012 0000004 echo -e '\0342\0230\0240' # uses the "0nnn" format, make sure it prints ☠ 

Il y a une différence dans la façon dont la valeur octale est exprimée dans Bash avec l' echo embedded ( 0nnn ) par rapport au truch d'outil tr ici ( nnn ):

Le caractère '\' suivi de 1, 2 ou 3 numbers octaux représente le caractère dont le code octet est donné par ces numbers. Les caractères multi-octets peuvent être spécifiés sous la forme d'une séquence d'octets octaux.

Essayons. L'option -dc supprime simplement le complément de SET1. Vous spécifiez un seul set, et tout élément de l'input standard qui ne contient aucun élément de l'set est supprimé:

 echo '012345' | /usr/5bin/tr -dc '456' #sanity check 45 #all good 

Maintenant ceux-ci:

 echo -e '\0342\0230\0240' | /usr/5bin/tr -dc '\342\230\240' echo -e '☠' | /usr/5bin/tr -dc '☠' 

qui devrait à la fois imprimer un (1) ☠, ou finalement le suivant (beaucoup plus de caractères) produisent tous la même erreur:

 /usr/5bin/tr -dc '\342\230\240' < /dev/urandom *** Error in `/usr/5bin/tr': double free or corruption (!prev): 0x0000000000d24420 *** 

En fait, chaque fois que l'input et SET1 contiennent le caractère choisi, l'erreur apparaît avec -dc . Le comportement est également le même dans les versions SysV 3rd, 4th, Posix, Posix2001 ou ucb (BSD) de la command fournie dans le toolchest. Parfois, comme dans le cas de tr -dc '1' < /dev/urandom je reçois un segfault correct ou quelques lignes de sortie suivies de ceci:

 Error in `/usr/5bin/tr': realloc(): invalid pointer: 0x00007f93ee284010 *** ======= Backtrace: ========= /usr/lib/libc.so.6(+0x73f8e)[0x7f93ee338f8e] /usr/lib/libc.so.6(+0x7988e)[0x7f93ee33e88e] /usr/lib/libc.so.6(realloc+0x1c8)[0x7f93ee342918] /usr/5bin/tr[0x401a74] /usr/5bin/tr[0x400e93] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f93ee2e5000] /usr/5bin/tr[0x400f63] ======= Memory map: ======== 00400000-00403000 r-xp 00000000 08:21 1579535 /usr/5bin/tr 00602000-00603000 rw-p 00002000 08:21 1579535 /usr/5bin/tr 0067a000-006bc000 rw-p 00000000 00:00 0 [heap] 7f93edc6e000-7f93edc84000 r-xp 00000000 08:21 1448153 /usr/lib/libgcc_s.so.1 7f93edc84000-7f93ede83000 ---p 00016000 08:21 1448153 /usr/lib/libgcc_s.so.1 7f93ede83000-7f93ede84000 rw-p 00015000 08:21 1448153 /usr/lib/libgcc_s.so.1 7f93ede84000-7f93ee2c5000 rw-p 00000000 00:00 0 7f93ee2c5000-7f93ee469000 r-xp 00000000 08:21 1440453 /usr/lib/libc-2.19.so 7f93ee469000-7f93ee669000 ---p 001a4000 08:21 1440453 /usr/lib/libc-2.19.so 7f93ee669000-7f93ee66d000 r--p 001a4000 08:21 1440453 /usr/lib/libc-2.19.so 7f93ee66d000-7f93ee66f000 rw-p 001a8000 08:21 1440453 /usr/lib/libc-2.19.so 7f93ee66f000-7f93ee673000 rw-p 00000000 00:00 0 7f93ee673000-7f93ee694000 r-xp 00000000 08:21 1440340 /usr/lib/ld-2.19.so 7f93ee6eb000-7f93ee874000 r--p 00000000 08:21 1448356 /usr/lib/locale/locale-archive 7f93ee874000-7f93ee877000 rw-p 00000000 00:00 0 7f93ee891000-7f93ee893000 rw-p 00000000 00:00 0 7f93ee893000-7f93ee894000 r--p 00020000 08:21 1440340 /usr/lib/ld-2.19.so 7f93ee894000-7f93ee895000 rw-p 00021000 08:21 1440340 /usr/lib/ld-2.19.so 7f93ee895000-7f93ee896000 rw-p 00000000 00:00 0 7fffed79c000-7fffed7bd000 rw-p 00000000 00:00 0 [stack] 7fffed7e9000-7fffed7eb000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 

Est-ce que tout cela suggère une erreur de compilation de ma part ou est-ce que je ne l'utilise pas correctement?


Avec le patch fourni , nous avons:

 echo -e '\0342\0230\0240' | /home/me/bin/trsc -dc '\342\230\240' echo -e '☠' | /home/me/bin/trsc -dc '☠' ☠ 

Comme nous devrions !! Mais:

 /home/me/bin/trsc -dc '\342\230\240' < /dev/urandom 

rest toujours un mystère car le personnage choisi n'est pas dans la sortie …

J'ai vu ça avant. Un bug. Essayer:

 --- tr.c 6 Sep 2005 23:04:11 -0000 1.10 +++ tr.c 30 May 2014 09:46:33 -0000 @@ -291,7 +291,6 @@ if(c<ccnt) code[c] = d; if(d<ccnt && sflag) squeez[d] = 1; } - free(vect); while((d = next(&ssortingng2)) != NIL) { if(sflag) squeez[d] = 1; if(ssortingng2.max==NIL && (ssortingng2.p==NULL || *ssortingng2.p==0)) 

(il s'agissait d'un coup d'oeil rapide il y a quelques mois, alors que ce patch va vous faire avancer, je ne peux pas vous garantir qu'il est correct.) Appliquer avec le patch -l ).

Notez également que /dev/urandom fournit un stream d' octets . En UTF-8, toutes les séquences d'octets ne correspondent pas aux caractères valides. Par exemple, 0x41 0x81 0x41 n'est pas valide car 0x81 est >= 0x80, donc il ne peut se produire que dans une séquence de 2 ou plus sur 0x80 octets.

Un octet invalide, car il n'est pas dans l'set des caractères qui est le complément de ☠, ne sera pas supprimé par tr .

Mieux serait probablement:

 recode ucs-2..u8 < /dev/urandom | tr -cd ☠ 

ucs-2 étant les caractères U + 0000 à U + FFFF codés sur 2 octets par caractère, /dev/urandom ressemble davantage à un stream de caractères ucs-2. (nous manquons les caractères U + 10000 à U + 10FFFF cependant).

Mais cela inclurait toujours la gamme de paires de substitution D800..DFFF sur laquelle mbrtowc(3) va s'étouffer (au less avec ma version de la libc).

Ces points de code sont réservés à l'enencoding UTF-16. d800dc00 par exemple est le encoding UTF-16BE de U + 10000, mais il n'y a pas de caractère U + D800 ou U + DC00. Le encoding UTF-8 de ceux-ci n'a pas de sens en tant que caractère (même s'il est adjacent).

Donc vous devriez d'abord les exclure:

 perl -ne 'BEGIN{$/=\2;binmode STDOUT,":utf8"} $c = unpack("n",$_); if ($c < 0xd800 || $c > 0xdfff) { no warnings "utf8"; print chr($c) }' < /dev/urandom | tr -cd ☠ 

Si le but est d'get un stream de caractères Unicode randoms codés en UTF-8, il est préférable d'get un sharepoint code random dans la plage autorisée (0..0xd7ff, 0xf000..0x10ffff) et de la convertir en UTF-8. Si vous voulez le baser sur /dev/urandom , vous pouvez utiliser 3 octets (24 bits) pour chaque sharepoint code:

 perl -ne 'BEGIN{$/=\3;binmode STDOUT,":utf8"} $c = unpack("N","\0$_") * 0x10F800 >> 24; $c+=0x800 if $c >= 0xd800; do {no warnings "utf8"; print chr($c)}' < /dev/urandom | tr -cd ☠