Heirloom Toolchest tr: 멀티바이트 문자가 포함된 컬렉션의 보완물을 제거하는 동안 오류가 발생했습니까?

Heirloom Toolchest tr: 멀티바이트 문자가 포함된 컬렉션의 보완물을 제거하는 동안 오류가 발생했습니까?

나는 사용하려고tr명령은 다음에서 비롯됩니다.가보 도구 상자극복하다현재 한도~의핵심 도구-dc"임의" 생성기에서 멀티바이트 문자를 "펌프"(옵션 사용) 할 수 있도록 구현되었습니다 (/dev/urandom) 터미널까지. 이것이 이미 있다는 점은 주목할 가치가 있습니다.컴파일된소스에서 시작아치방AUR 사용 실패 후버전.

이를 단순화하기 위해 문자(☠)를 선택하고 해당 8진수 값을 파악해 보겠습니다. 이는 도구 상자에 대해 다음과 같이 표현되어야 하기 때문입니다 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

8진수 값을 표현하는 방식에 차이가 있습니다불다그리고echo 내장(0nnn) 여기의 도구 상자 tr(에 에):

문자 "\" 뒤에 1, 2, 3개의 8진 숫자가 오면 해당 숫자로 바이트코드가 제공되는 문자를 나타냅니다. 멀티바이트 문자는 8진수 바이트 시퀀스로 지정할 수 있습니다.

해 보자. 이 -dc옵션은 단순히 SET1의 보수를 삭제합니다. 세트를 지정하면 해당 세트의 요소를 포함하지 않는 표준 입력의 모든 항목이 삭제됩니다.

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

이제 이것들은:

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

둘 다 one(1)☠을 인쇄해야 합니다. 그렇지 않으면 궁극적으로 다음(더 많은 문자)이 모두 동일한 오류를 생성합니다.

/usr/5bin/tr -dc '\342\230\240' < /dev/urandom

*** Error in `/usr/5bin/tr': double free or corruption (!prev): 0x0000000000d24420 ***

실제로 입력과 SET1에 모두 선택한 문자가 포함될 때마다 오류가 발생하고 가 표시됩니다 -dc. 이 동작은 시스템 전체에서도 동일합니다.SysV 3rd, 4th, Posix, Posix2001 또는 ucb(BSD)도구 상자에 제공되는 명령 버전입니다. 때로는 tr -dc '1' < /dev/urandom적절한 segfault나 몇 줄의 출력이 나타나는 경우도 있습니다.

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]

이것은 내 부분의 컴파일 오류를 의미합니까, 아니면 올바르게 사용하지 않는 것입니까?


기여로수리하다우리는:

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

우리가 그래야 하는 것처럼! 하지만:

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

선택한 캐릭터가 출력되지 않는다는 점은 여전히 ​​수수께끼입니다...

답변1

나는 그것을 본 적이 있다. 실수. 노력하다:

--- 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(&string2)) != NIL) {
                if(sflag) squeez[d] = 1;
                if(string2.max==NIL && (string2.p==NULL || *string2.p==0))

(이것은 몇 달 전의 간략한 모습이며 이 패치를 통해 앞으로 나아갈 수 있지만 그것이 정확하다고 보장할 수는 없습니다. Apply 를 사용하십시오 patch -l.)

이제 /dev/urandom스트림도 제공됩니다.바이트. UTF-8에서는 모든 바이트 시퀀스가 ​​유효한 문자에 매핑되는 것은 아닙니다. 예를 들어 0x41 0x81 0x41은 0x80 0x81이므로 유효하지 않으므로 >=0x80바이트를 넘어서 2바이트 이상의 시퀀스로만 나타날 수 있습니다.

☠의 보완 문자 집합에 포함되지 않아 제거되지 않으므로 잘못된 바이트입니다 tr.

더 나은 방법은 다음과 같습니다.

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

Ucs-2는 U+0000부터 U+FFFF까지의 문자이며, 각 문자는 2바이트로 인코딩되며 /dev/urandomucs-2 문자 스트림과 더 비슷해 보입니다. (그러나 U+10000에서 U+10FFFF까지의 문자가 누락되었습니다.)

하지만 여기에는 여전히 포함됩니다.D800..DFFF 프록시 쌍 범위 이것은 mbrtowc(3)숨막히는 일입니다(적어도 내 버전의 libc에서는).

이러한 코드 포인트는 UTF-16 인코딩용으로 예약되어 있습니다. 예를 들어 d800dc00은 U+10000의 UTF-16BE 인코딩이지만 U+D800 문자 또는 U+DC00은 없습니다. 이러한 문자의 UTF-8 인코딩도 의미가 없습니다(인접한 경우에도).

따라서 먼저 제외해야 합니다.

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 ☠

목표가 UTF-8로 인코딩된 임의의 유니코드 문자 스트림을 얻는 것이라면 허용된 범위(0..0xd7ff, 0xf000..0x10ffff) 내에서 임의의 코드 포인트를 가져와 UTF-8로 변환하는 것이 좋습니다. 을 기반으로 하려는 경우 /dev/urandom각 코드 포인트에 대해 3바이트(24비트)를 사용할 수 있습니다.

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 ☠

관련 정보