첫 번째에서 후속 질문, ToPtr
의 구현은 불건전 한 코드를 초대합니다. 여기에 재현 :
이
// code in italics is wrong
impl ToPtr for str {
fn to_ptr(&self) -> *const i8 {
CString::new(self).unwrap().as_ptr()
}
}
이 새로운 CString
를 할당하고 그 내용에 대한 포인터를 반환하지만 CString
때 to_ptr
수익률을 삭제, 그래서 이것은 허상 포인터입니다. 이 포인터의 역 참조는 정의되지 않은 동작입니다.documentation에는 이에 대한 큰 경고가 있지만 여전히 흔한 실수입니다.
*const c_char
을 문자열 리터럴로 만드는 올바른 방법은 b"string here\0".as_ptr() as *const c_char
입니다. 문자열은 null로 끝나며 문자열 리터럴이 전체 프로그램에 있기 때문에 매달린 포인터가 없습니다. 당신이 변환 할 아닌 상수 문자열이있는 경우는 사용하는 동안, 당신은 이처럼 CString
생존을 유지해야합니다 제외하고
let s = "foo";
let cs = CString::new(s).unwrap(); // don't call .as_ptr(), so the CString stays alive
unsafe { some_c_function(cs.as_ptr()); }
// CString is dropped here, after we're done with it
은 : 편집자는 "제안"(난 ,
let s = "foo";
unsafe {
// due to temporary drop rules, the CString will be dropped at the end of the statement (the `;`)
some_c_function(CString::new(s).unwrap().as_ptr());
}
를이 (올바른 최고의 종류) 기술적으로 정확하지만 : 새로운 스택 오버플로,하지만 그것을 언급하는 대신 위의 코드는 다음과 같이 기록 될 수 있다는) 내 대답을 다시 시도하는 것이 더 정중 보인다 관련된 "임시 삭제 규칙"은 미묘합니다. - as_ptr
는 CString
참조 걸리기 때문에 (실제로 &에서는 CStr를 컴파일러하여 CString에있어서 사슬 : 새로운 (S) .unwrap()을 변경하기 때문에, DEREF()를 as_ptr()..)이 작동 그것을 소비하는 대신 C 함수를 하나만 호출 할 수 있기 때문입니다. 안전하지 않은 코드를 작성할 때 미묘하거나 분명하지 않은 것에 의존하고 싶지 않습니다. 방법 중 그와
, 당신의 코드에서
fixed that unsoundness (통화 모두 사용 문자열 리터럴 난 그냥 위의 내 첫 번째 전략을 사용하므로).OSX에서이 출력을 얻었습니다.
0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 0
0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0
0, 0, 4, 3, 0, 0, 0, 0, 0, 0, 0
이렇게 결과가 일치합니까? 또한 다음과 같은 C 프로그램 작성 :
#include <stdio.h>
#include <unistd.h>
int main() {
struct __sFILE *fp1 = fdopen(STDIN_FILENO, "r");
struct __sFILE *fp2 = fdopen(STDOUT_FILENO, "w");
struct __sFILE *fp3 = fdopen(STDERR_FILENO, "w");
struct __sFILE *passwd = fopen("/etc/passwd", "r");
printf("%i %i %i %i\n", fp1->_flags, fp2->_flags, fp3->_flags, passwd->_flags);
}
을 그리고 출력있어 :
4 8 8 4
녹 결과를 옹호 것으로 보인다.
/*
* The following always hold:
*
* if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
* _lbfsize is -_bf._size, else _lbfsize is 0
* if _flags&__SRD, _w is 0
* if _flags&__SWR, _r is 0
*/
그리고 찾는 사람들 상수 :
#define __SLBF 0x0001 /* line buffered */
#define __SRD 0x0004 /* OK to read */
#define __SWR 0x0008 /* OK to write */
이것은 우리가 얻을 출력과 일치하는 것 같다 읽기 모드에서 열 파일을 4, 8 말한다 /usr/include/stdio.h
의 상단에 의견이 있습니다 쓰기. 그러면 여기서 어떤 문제가 발생합니까?
게시 한 코드가 컴파일되지 않습니다 (fp와 passwd의 혼란이라고 생각합니다). 또한 C 함수에 전달한 문자열은 NUL로 끝나지 않으므로 코드에는 완전히 정의되지 않은 동작이 있습니다. –
오 그래, NUL 종료를 수행하는 하나의 파일을 추가하는 것을 잊어 버렸습니다. 위의 요지를 업데이트했습니다. – hansaplast
매번 문자열 누출이 걱정되지 않습니까? 어쨌든, 두 번째 주장은 똑같은 문제가 있다고 생각합니다. –