긴 문자열을 tr로 전송하면 중단 및 CPU 스파이크가 발생합니다.

긴 문자열을 tr로 전송하면 중단 및 CPU 스파이크가 발생합니다.

MacOS 요세미티(10.10.5). 나는 이것이 Unix/Linux 부분이라는 것을 알고 있지만... 이 질문은 MacOS 영역보다 더 관련성이 있을 것이라고 생각했습니다.

내 터미널은 시작 시 중단되기 시작하고 프롬프트를 표시하며 동시에 CPU 사용량이 급증합니다. CTRL-C를 누르면 메시지가 표시됩니다(아마도 보류 중/실행 중인 일부 .bashrc/.profile/etc를 종료하라는 메시지가 표시될 것임).

나는 .bashrc의 특정 라인이 중단을 유발한다는 것을 금방 발견했습니다. 이것은 새로운 것입니다(즉, .bashrc에서 아무것도 변경하지 않았으며 모든 것이 잘 작동합니다). 그래서 시스템에서 뭔가가 변경되었습니다.

특정 긴 문자열을 파이핑하면 정지/CPU 스파이크가 발생하는 것 같습니다.

끈을 파이핑하여 tr -d '\n'끈이 있는지 확인하여 이를 재현할 수 있습니다.

macattack:~ $ openssl rand -base64 93  | tr -d '\n'
eDsz4JqFX/HAVjplNI6WDWwPRp9l9snp6UKp/pLn+GbBvJx0+ZMvSJFS/SuCwjMRRXVXfUvBdkaH1R0UgCr2UOf283MvHVTRusLFEVPcGCIz1t3sFMU/3foRzNWVmattp@macattack:~ $ openssl rand -base64 94 | tr -d '\n'
^C
mattp@macattack:~ $ openssl rand -base64 94 | tr -du '\n'
^C

tr이 매달리기 시작하는 마법의 숫자는 93자인 것 같습니다. openssl이 중단되지 않습니다(즉, 모든 송신 파이프를 제거한 경우 tr). 그러나 원래 문제의 줄 길이가 달랐습니다.

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log;' | tr -d '\n'
^C-bash: echo: write error: Interrupted system call

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log' | tr -d '\n'

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log' | wc -c
     128
mattp@macattack:~ $

tr이는 문제라기 보다는 배관 문제일 수 있습니다 . 동일한 문제를 재현할 수 있습니다 sed(명령이 의미가 없습니다...단지 중단만 표시됩니다).

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log;'  | sed 's/\n/ /g'
^C-bash: echo: write error: Interrupted system call

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log'  | sed 's/\n/ /g'
echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log
mattp@macattack:~

이 문제에 대한 해결책이 부족합니다.
정지 명령은 임의의 Centos Linux 서버에서 제대로 실행됩니다. 최근까지 이러한 명령은 macOS에서 제대로 작동했습니다. 나는 이전에 파이프가 매달린 상황을 겪어본 적이 없습니다. 입력의 이상한 문자가 문제의 원인이라고 생각했지만 openssl 임의 문자열은 그렇지 않은 것으로 표시됩니다. ulimit는 동일한 문제가 없는 다른 Mac과 동일합니다.

mattp@macattack:~ $ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 7168
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 709
virtual memory          (kbytes, -v) unlimited

dtruss이를 사용하면 trread_nocancel 호출이 중단되는 것 같습니다.

고쳐 쓰다

함께 지내다. 행잉 및 파이프 버퍼 크기에 대한 의견을 찾았습니다. 여기에서 훔친 테스트 스크립트: 파이프 버퍼는 얼마나 큽니까?

문제가 발생하면 런타임에 파이프 버퍼가 128바이트인 것으로 표시됩니다. 재부팅되었으며(문제가 일시적으로 사라짐) 파이프 버퍼는 65536바이트입니다. 아래 테스트 출력을 참조하세요.

이제 문제는 "뭔가"가 시스템의 파이프 버퍼 크기를 줄이는 이유/방법입니다.

문제가 있다

$ /bin/bash -c 'for p in {0..18}; do pipe-buffer-test.sh $((2 ** $p)) 0.5; done'
write size:          1; bytes successfully before error: 128
write size:          2; bytes successfully before error: 128
write size:          4; bytes successfully before error: 128
write size:          8; bytes successfully before error: 128
write size:         16; bytes successfully before error: 128
write size:         32; bytes successfully before error: 128
write size:         64; bytes successfully before error: 128
write size:        128; bytes successfully before error: 128
write size:        256; bytes successfully before error: 0
write size:        512; bytes successfully before error: 0
write size:       1024; bytes successfully before error: 0
write size:       2048; bytes successfully before error: 0
write size:       4096; bytes successfully before error: 0
write size:       8192; bytes successfully before error: 0
write size:      16384; bytes successfully before error: 0
write size:      32768; bytes successfully before error: 0
write size:      65536; bytes successfully before error: 0
write size:     131072; bytes successfully before error: 0
write size:     262144; bytes successfully before error: 0

다시 시작한 후(문제가 일시적으로 사라짐)

$ /bin/bash -c 'for p in {0..18}; do pipe-buffer-test.sh $((2 ** $p)) 0.5; done'
write size:          1; bytes successfully before error: 65536
write size:          2; bytes successfully before error: 65536
write size:          4; bytes successfully before error: 65536
write size:          8; bytes successfully before error: 65536
write size:         16; bytes successfully before error: 65536
write size:         32; bytes successfully before error: 65536
write size:         64; bytes successfully before error: 65536
write size:        128; bytes successfully before error: 65536
write size:        256; bytes successfully before error: 65536
write size:        512; bytes successfully before error: 65536
write size:       1024; bytes successfully before error: 65536
write size:       2048; bytes successfully before error: 65536
write size:       4096; bytes successfully before error: 65536
write size:       8192; bytes successfully before error: 65536
write size:      16384; bytes successfully before error: 65536
write size:      32768; bytes successfully before error: 65536
write size:      65536; bytes successfully before error: 65536
write size:     131072; bytes successfully before error: 0
write size:     262144; bytes successfully before error: 0

답변1

커널 버퍼 누출에 대한 @Barmar의 의견을 바탕으로 현재 비 OS kext를 살펴보았습니다. 최근에 설치된 BlockBlock이 비교적 새로운 것이 있다는 것을 깨달았습니다.https://objective-see.com/products/blockblock.html).

BlockBlock을 제거하고 다시 시작했는데 문제가 다시 나타나지 않았습니다. 그래서 이 경우에는 BlockBlock이 범인이었고 작성자에게 이 문제를 보고했습니다.

그러나 이는 원인을 파악하기 위해 대부분 추측 및 확인 접근 방식을 취하고 있기 때문에 특별히 만족스럽지 않습니다. 솔직히 말해서 근본 원인을 잘 이해하지 못합니다(OS에 관한 한). ), 이는 앞으로는 이러한 문제를 더 현명하게 해결하지 않을 것이라는 의미입니다.

누구든지 이 문제를 겪고 무슨 일이 일어나고 있는지 더 자세히 설명하고 문제 해결을 제공할 수 있다면 "BlockBlock 제거"보다 더 나은 대답이 될 것입니다.

관련 정보