터미널에서 실행하면 아직 입력이 없는 한 hexdump
, , 등과 같은 ^D
줄 시작 부분에 있는 단일 항목에 반응 하지 않습니다.cat
od
bc
prompt% hexdump -C
<control-D>
prompt% hexdump -C
hello
<control-D><control-D> # a single ^D won't do
00000000 68 65 6c 6c 6f 0a |hello.|
00000006
나는 이것을 fedora 28과 debian 9에서 재현할 수 있습니다. hexdump
Debian에서 제공 하지만 bsdmainutils
bsd에서는 이런 일이 발생하지 않습니다.
이건 그냥 버그인가요? 이 동작을 나타내는 것으로 알려진 다른 프로그램이 있습니까?
답변1
@JdeBP 감사합니다힌트, 동일한 작업을 수행하는 작은 테스트 케이스를 만들 수 있었습니다 hexdump
.
#include <stdio.h>
int main(void){
char buf[64]; size_t r;
for(;;){
printf("eof=%d, error=%d\n", feof(stdin), ferror(stdin));
r = fread(buf, 1, sizeof buf, stdin);
printf("read %zd bytes, eof=%d, error=%d\n",
r, feof(stdin), ferror(stdin));
if(!r) return 0;
}
}
glibc 기반 시스템(일반적인 Linux 데스크탑)에서 실행하는 경우.
prompt$ ./fread-test
eof=0, error=0
<control-D>
read 0 bytes, eof=1, error=0
prompt$ ./fread-test
eof=0, error=0
hello
<control-D>
read 6 bytes, eof=1, error=0
eof=1, error=0
<control-D>
read 0 bytes, eof=1, error=0
bsd, Solaris, busybox(uclibc), android 등에서 실행하는 경우:
prompt$ ./fread-test
eof=0, error=0
hello
<control-D>
read 6 bytes, eof=1, error=0
eof=1, error=0
read 0 bytes, eof=1, error=0
표준에 대한 나의 비전문적인 해석을 바탕으로 보면 다음과 같습니다.허점glibc(GNU C 라이브러리)에서.
~에 대한fread
:
각 객체에 대해 fgetc() 함수에 대한 크기 호출이 이루어져야 하며 결과는 객체를 정확히 포함하는 부호 없는 문자 배열에 읽기 순서로 저장되어야 합니다.
~에 대한fgetc
:
stream이 가리키는 입력 스트림의 파일 끝 표시기가 설정되지 않은 경우그리고 다음 바이트가 존재하면, fgetc() 함수는 다음 바이트를 얻어야 합니다
eof 표시기가 설정되어 있어도 glibc는 "다음 바이트 가져오기"를 시도하는 것 같습니다.
실제로 그것은실제로는GNU C 라이브러리의 버그는 BSD 또는 musl C 라이브러리에 존재하지 않습니다. 2005년 초에 이미 알려짐. Ulrich Drepper는 2007년에 버그 보고를 종료했지만 버그를 수정하지 않았습니다. 2012년에 논의됨, 이는 다른 C 라이브러리에는 이러한 동작이 없으며 1999년 C 표준은 이에 대해 매우 구체적이며 Solaris는 c99
대신 컴파일러로 사용될 때 이를 위한 특별한 메커니즘도 가지고 있습니다 cc
.
2018년에 마침내 수정됨. 이 문제는 GNU C 라이브러리 버전 2.28에서 수정되었습니다. 현재 "안정적인" 데비안 버전인 버전 9는GNU C 라이브러리 버전 2.24에 위치, 따라서 버그는 보고된 지 14년이 지난 후에도 계속해서 나타납니다.
GNU C 라이브러리 토론에서 지적했듯이,가능성다른 C 라이브러리(예: musl) 또는 다른 플랫폼의 동작에 관계없이 GNU C 라이브러리의 특성을 요구하는 소프트웨어를 작성하세요. 그러나 위에서 언급한 수년간의 논의 동안 그러한 계획은 확정되지 않았습니다. 일부 프로그램은 이전 GNU C 라이브러리에 의해 손상되어 사용자가 EOF 신호를 두 번 연속 보내야 합니다.가지다hexdump
여기에는 다른 사람도 포함됩니다.patch
StackOverflow의 2018년.
답변2
추적 출력
…
read(0, "hello\n", 1024) = 6
read(0, "", 1024) = 0
read(0, "hello\n", 1024) = 6
read(0, "", 1024) = 0
read(0, "", 1024) = 0
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 11), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8dd4cef000
write(1, "0000000 h e l l o \\n "..., 72) = 72
write(1, "000000c\n", 8) = 8
exit_group(0) = ?
+++ exited with 0 +++
여기에서는 hello «ctrl-d» hello «ctrl-d» «ctrl-d»를 입력했습니다(두 번째 hello는 로그 출력에서 잘립니다). 그래서 이렇게 프로그래밍한 것 같습니다.
추적 실행
- 두 개의 터미널을 엽니다
- 첫 번째 유형에서는
ll /proc/self/fd/1
- 두 번째 유형에서는
strace hexdump -C 2>/dev/pts/«number-at-end-of-output-of-previous-command»