Rust: const index out-of-bound 쑰건을 더 일찍 λ³΄κ³ ν•˜μ‹­μ‹œμ˜€.

에 λ§Œλ“  2012λ…„ 08μ›” 10일  Β·  24μ½”λ©˜νŠΈ  Β·  좜처: rust-lang/rust

ν˜„μž¬ const exprμ—μ„œ const 벑터에 λŒ€ν•œ 인덱싱을 μ‹œλ„ν•˜λ©΄ λ²ˆμ—­ 쀑 컴파일 ν›„λ°˜μ— 경계 μ˜€λ²„λŸ°μ΄ λ³΄κ³ λ©λ‹ˆλ‹€. const 평가 λ‹¨κ³„μ—μ„œ 더 일찍 μ•Œμ•„μ°¨λ €μ•Ό ν•©λ‹ˆλ‹€.

A-diagnostics C-cleanup P-low T-compiler

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

λ„€, 6λ…„ λ§Œμ— 이 문제λ₯Ό 끝낸 것 κ°™μ•„μš”.μ›ƒμŒ:

λͺ¨λ“  24 λŒ“κΈ€

λΆ„λͺ…νžˆ 이것이 μƒμ„±ν•˜λŠ” "였λ₯˜"λŠ” 컴파일 μ‹€νŒ¨λ₯Ό μΌμœΌν‚€μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ½”λ“œκ°€ μƒμ„±λ˜κ³  rustcλŠ” 0을 λ°˜ν™˜ν•©λ‹ˆλ‹€. μΈλ±μŠ€κ°€ 물리적으둜 λ²”μœ„λ₯Ό λ²—μ–΄λ‚˜λ©΄ LLVM은 λΆˆν‰ν•  것이며, μ΄λŠ” ν˜„μž¬ 항상 λ²”μœ„λ₯Ό λ²—μ–΄λ‚œ 것과 λ™μΌν•©λ‹ˆλ‹€. index (λ‚΄ 생각에) ν•˜μ§€λ§Œ const 슬라이슀의 κ²½μš°μ—λŠ” 그렇지 μ•ŠμŠ΅λ‹ˆλ‹€.

이것은 ν…ŒμŠ€νŠΈ 쀑에 특히 μ˜ˆμƒμΉ˜ λͺ»ν•œ 일이며(λΉ λ₯Έ 확인을 μ œμ™Έν•˜κ³ λŠ” λΆ„λͺ…νžˆ?) 성곡 μ‹œ 좜λ ₯/였λ₯˜λ₯Ό ν‘œμ‹œν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

0.6μ—μ„œλŠ” μ€‘μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ””λ§ˆμΌμŠ€ν†€

λ§ˆμΌμŠ€ν†€ 5 후보 지λͺ…, 생산 μ€€λΉ„ μ™„λ£Œ

생산 μ€€λΉ„ μ΄μ •ν‘œ 승인

이것이 μ΄μ•ΌκΈ°ν•˜κ³  μžˆλ‹€κ³  μƒκ°ν•˜λŠ” κ²ƒμ˜ μ˜ˆλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

static a: &'static [int] = &[];
static b: int = a[1];

fn main() {}

수읡λ₯ 

$ rustc foo.rs
foo.rs:2:16: 2:19 error: const index-expr is out of bounds
foo.rs:2 static b: int = a[1];
                         ^~~
Assertion failed: (ReqTy && "extractvalue indices invalid!"), function getExtractValue, file ../../../../src/llvm/lib/IR/Constants.cpp, line 1982.
zsh: abort      rustc foo.rs

μš°λ¦¬κ°€ LLVM μ£Όμž₯을 ν•˜κ³  μžˆλŠ” 것이 λ‚˜μœ 것 κ°™μŠ΅λ‹ˆλ‹€.

P-low에 λŒ€ν•΄ ν—ˆμš©λ©λ‹ˆλ‹€.

λΆ„λ₯˜: @alexcrichton 의 (9κ°œμ›” 된) μ˜ˆμ œλŠ” μ—¬μ „νžˆ ꡬ문적으둜 μœ νš¨ν•˜λ©°(예!) ν•΄λ‹Ή μ£Όμž₯κ³Ό ν•¨κ»˜ μ—¬μ „νžˆ μ‹€νŒ¨ν•©λ‹ˆλ‹€(우!).

λ‚˜λŠ” 이것이 λ―ΏμŠ΅λ‹ˆλ‹€ κ³ μ • .

@alexcrichton 의 예λ₯Ό μ—…λ°μ΄νŠΈν•˜λŠ” 경우:

#![allow(dead_code)]
const A: &'static [usize] = &[];
const B: usize = A[1];

fn main() {}

이제 뢈만 없이 μ„±κ³΅μ μœΌλ‘œ μ»΄νŒŒμΌλ©λ‹ˆλ‹€.

잘λͺ»λœ κ°’ B 을 μ‚¬μš©ν•˜λ €κ³  μ‹œλ„ν•˜λ©΄ rustc 에 λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€.

#![allow(dead_code)]
const A: &'static [usize] = &[];
const B: usize = A[1];

fn main() {
    println!("B={}", B);
}
<anon>:3:18: 3:22 error: const index-expr is out of bounds
<anon>:3 const B: usize = A[1];
                          ^~~~
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/lib/IR/Constants.cpp:2174: static llvm::Constant* llvm::ConstantExpr::getExtractValue(llvm::Constant*, llvm::ArrayRef<unsigned int>, llvm::Type*): Assertion `ReqTy && "extractvalue indices invalid!"' failed.
Aborted (core dumped)
playpen: application terminated with error code 134

였λ₯˜: κ°’μœΌλ‘œ λ‹€λ₯Έ 톡계λ₯Ό μ°Έμ‘°ν•  수 μ—†μŠ΅λ‹ˆλ‹€. λŒ€μ‹  μ£Όμ†Œ μ—°μ‚°μž λ˜λŠ” μƒμˆ˜λ₯Ό μ‚¬μš©ν•˜μ‹­μ‹œμ˜€.

예, 쒋은 것 κ°™μŠ΅λ‹ˆλ‹€.

잠깐, @JustAPerson 의 μ˜ˆλŠ” λ‚˜μ—κ²Œ 쒋지 μ•Šμ€ 것 κ°™μŠ΅λ‹ˆλ‹€. 재개μž₯.

λ‚˜λŠ” 이것이 이제 μ‹€μ œλ‘œ μˆ˜μ •λ˜μ—ˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

$ cat foo.rs
#![allow(dead_code)]
const A: &'static [usize] = &[];
const B: usize = A[1];

fn main() {
    println!("B={}", B);
}
$ rustc foo.rs
foo.rs:3:18: 3:22 error: const index-expr is out of bounds
foo.rs:3 const B: usize = A[1];
                          ^~~~
error: aborting due to previous error
$ rustc --version
rustc 1.0.0-dev (a691f1eef 2015-04-15) (built 2015-04-15)

κ·Έλž˜μ„œ μ§€λ‚œ 11일 λ™μ•ˆ:

hello.rs:3:18: 3:22 error: const index-expr is out of bounds
hello.rs:3 const B: usize = A[1];
                            ^~~~
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/include/llvm/Support/Casting.h:237: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) [with X = llvm::SequentialType; Y = llvm::Type; typename llvm::cast_retty<X, Y*>::ret_type = llvm::SequentialType*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.

sooooλŠ” 이미 퇴보 ν•œ 것 κ°™μŠ΅λ‹ˆκΉŒ?

헐 이건 λ‚΄ μ‹€μˆ˜μ˜€μ–΄ LLVM μ–΄μ„€μ…˜μ΄ λΉ„ν™œμ„±ν™”λœ μƒνƒœλ‘œ 컴파일된 도ꡬ λͺ¨μŒμ„ μ‚¬μš©ν•˜μ—¬ μœ„μ˜ λ³΄κ³ μ„œλ₯Ό μž‘μ„±ν–ˆμŠ΅λ‹ˆλ‹€(기본값인지 λͺ°λžμŠ΅λ‹ˆλ‹€).

(μ•ˆλ…•ν•˜μ„Έμš”, μ €λŠ” μ‹ κ·œ μ΄λ―Όμžλ“€μ΄ E-easy λ¬Έμ œμ— 더 μ‰½κ²Œ μ ‘κ·Όν•  수 μžˆλ„λ‘ 돕기 μœ„ν•΄ λ…Έλ ₯ν•˜κ³ 

LLVM μ–΄μ„€μ…˜μ΄ λΉ„ν™œμ„±ν™”λœ μƒνƒœλ‘œ 컴파일된 도ꡬ λͺ¨μŒμ„ μ‚¬μš©ν•˜μ—¬ μœ„μ˜ λ³΄κ³ μ„œλ₯Ό μž‘μ„±ν–ˆμŠ΅λ‹ˆλ‹€(기본값인지 λͺ°λžμŠ΅λ‹ˆλ‹€).

이 문제λ₯Ό μž¬ν˜„ν•˜λ €λ©΄ 기본값이 μ•„λ‹Œ μ„€μ •μœΌλ‘œ 컴파일된 도ꡬ λͺ¨μŒμ„ μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆκΉŒ? κ·Έλ ‡λ‹€λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν• κΉŒμš”?

μ—¬κΈ°μ—μ„œ 무슨 일이 μΌμ–΄λ‚˜κΈ°λ‘œ λ˜μ–΄ μžˆλŠ”μ§€ ν˜Όλž€μŠ€λŸ½μŠ΅λ‹ˆλ‹€. λͺ¨λ“  마감-μž¬κ°œλ΄‰ 일이 진행 μ€‘μž…λ‹ˆλ‹€. λˆ„κ΅°κ°€κ°€ μ˜ˆμƒλ˜λŠ” λ™μž‘μ΄ 무엇이며 ν˜„μž¬ λ™μž‘κ³Ό μ–΄λ–»κ²Œ λ‹€λ₯Έμ§€ λͺ…ν™•νžˆ ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

./configure --enable-llvm-assertions

κ·ΈλŸ¬λ‚˜ LLVM μ£Όμž₯이 ν™œμ„±ν™”λ˜μ–΄ 있기 λ•Œλ¬Έμ— Rustλ₯Ό λ°€λ§ˆλ‹€ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. http://is.gd/X2RztVλŠ” μ—¬μ „νžˆ 야간에 μ–΄μ„€μ…˜μ— μ‹€νŒ¨ν•©λ‹ˆλ‹€.

<anon>:2:17: 2:21 error: const index-expr is out of bounds
<anon>:2 static b: i32 = a[1];
                         ^~~~
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/include/llvm/Support/Casting.h:237: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) [with X = llvm::SequentialType; Y = llvm::Type; typename llvm::cast_retty<X, Y*>::ret_type = llvm::SequentialType*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
Aborted (core dumped)
playpen: application terminated with error code 134

2013년에 κ³ λ―Όν–ˆλ˜ 것이 μˆ˜μ •λœ 것 κ°™μŠ΅λ‹ˆλ‹€. λ§Œμ•½ Rustcκ°€ const index-expr is out of bounds 였λ₯˜λ₯Ό μ œκ³΅ν•˜λ©΄ LLVM μ£Όμž₯이 λΉ„ν™œμ„±ν™”λ˜μ–΄λ„ μ‹€νŒ¨ μƒνƒœλ‘œ μ’…λ£Œλ©λ‹ˆλ‹€(좜λ ₯ νŒŒμΌμ„ μž‘μ„±ν•˜μ§€ μ•ŠμŒ). κ²€μ‚¬μ—μ„œ λˆ„λ½λœ 였λ₯˜λ₯Ό 찾을 수 μ—†μ–΄μ•Ό ν–ˆκΈ° λ•Œλ¬Έμ— 검사가 μˆ˜ν–‰ν•˜λŠ” μ„Έμ…˜/였λ₯˜ ν•­λͺ©μ— λŒ€ν•œ μ•‘μ„ΈμŠ€ κΆŒν•œμ΄ λ²ˆμ—­μ— μ—†μ—ˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ§€κΈˆμ€ 그렇지 μ•Šμ€ 것 κ°™μŠ΅λ‹ˆλ‹€.

λ‚΄ κ³Όκ±° μžμ‹ μ΄ μ–ΈκΈ‰ν•œ 또 λ‹€λ₯Έ 것은... λ²”μœ„λ₯Ό λ²—μ–΄λ‚¬λ‹€λŠ” 것을 μ•Œλ©΄μ„œλ„ 인덱슀λ₯Ό LLVM에 μ „λ‹¬ν•˜λŠ” κ²ƒμ²˜λŸΌ λ“€λ Έμ§€λ§Œ μ΄μ œλŠ” λŒ€μ‹  undef ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ§€κΈˆμ€ κ·Έ 였λ₯˜κ°€ μ œλŒ€λ‘œ μ²˜λ¦¬λ˜μ—ˆκΈ° λ•Œλ¬Έμ— μ–΄λ–€ κ²½μš°μ—λ„ κ·Έ 뢀뢄은 μ²˜λ¦¬λ©λ‹ˆλ‹€.

였늘 μš°λ¦¬κ°€ 보고 μžˆλŠ” LLVM μ£Όμž₯에 λŒ€ν•΄ μΆ”μΈ‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 였λ₯˜λ₯Ό λ³΄κ³ ν•œ ν›„ λ‹€μŒμ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€.

C_undef(type_of::type_of(cx, bt).element_type())

그리고 λ‚˜λŠ” μš°λ¦¬κ°€ λ‹€μŒκ³Ό 같은 것을 μ›ν•œλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€(ν…ŒμŠ€νŠΈλ˜μ§€ μ•ŠμŒ).

C_undef(val_ty(arr).element_type())

μΈλ±μ‹±λ˜λŠ” 값이 슬라이슀 λ˜λŠ” 포인터인 경우 bt (ν•΄λ‹Ή μœ ν˜•)λŠ” λ°°μ—΄ μœ ν˜•μœΌλ‘œ ν‘œμ‹œλ˜μ§€ μ•ŠμœΌλ―€λ‘œ element_type κ°€ μ‹€νŒ¨ν•©λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ @graydon 이 이 문제λ₯Ό

λ‚˜λŠ” 이것이 μ§€κΈˆ μ™„μ „νžˆ κ³ μ³μ‘Œλ‹€κ³  μƒκ°ν•œλ‹€. @oli-obk?

μ•„λ‹ˆμš”, check_const μ—μ„œ ν•΄κ²°ν•΄μ•Ό ν•˜κ³  ν˜„μž¬ 보고 μœ„μΉ˜λ₯Ό 버그 μœ„μΉ˜λ‘œ λ³€κ²½ν•΄μ•Ό ν•©λ‹ˆλ‹€.

@oli-obk 이것은 μ‰¬μš΄ ν”½μŠ€μΈκ°€μš”? κ·Έλ ‡λ‹€λ©΄ λ©˜ν† λ§μ„ ν•˜κ³  μƒˆλ‘œμš΄ μ‚¬μš©μžκ°€ ν¬λž™μ„ μ‹œλ„ν•  수 μžˆλ„λ‘ 힌트λ₯Ό λ‚¨κ²¨μ£Όμ‹œκ² μŠ΅λ‹ˆκΉŒ?

μ‰¬μš΄ μˆ˜μ •μ΄μ§€λ§Œ(기본적으둜 https://github.com/rust-lang/rust/blob/master/src/librustc/middle/check_const.rs#L470-L490을 훔쳐 ExprIndex μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€ unimplemented!() λ°”κΏ‰λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ μ‚¬μš©ν•˜μ§€ μ•Šμ€ const ARR: [u32; 0] = []; const X: u32 = ARR[5]; ν˜„μž¬ 컴파일 였λ₯˜λ₯Ό μΌμœΌν‚€μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μ΄λŠ” λ˜ν•œ 획기적인 변경이 될 κ²ƒμž…λ‹ˆλ‹€. 그리고 check_const λŠ” μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μƒμˆ˜λ„ ν™•μΈν•©λ‹ˆλ‹€.

λ˜ν•œ λͺ¨λ“  const 평가λ₯Ό 두 번 μˆ˜ν–‰ν•˜κ²Œ λ©λ‹ˆλ‹€. μƒμˆ˜λ₯Ό μΊμ‹±ν•˜μ—¬ λ¬Έμ œκ°€ 되면 ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ¬Όλ‘  const_err 보푸라기λ₯Ό λ‚΄λ³΄λ‚΄λŠ” κ²ƒμœΌλ‘œ μ£Όμš” λ³€κ²½ 사항을 ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이것은 LLVM μ–΄μ„€μ…˜μ΄ μ•„λ‹Œ μ‚¬μš© μ‹œ E0080 을 λ˜μ§€κΈ° λ•Œλ¬Έμ— (MIRI둜 인해) 'ν•΄κ²°λœ' κ²ƒμœΌλ‘œ λ³΄μž…λ‹ˆλ‹€. μ•‘μ„ΈμŠ€κ°€ μ‚¬μš©λ˜μ§€ μ•ŠμœΌλ©΄ μ—¬μ „νžˆ ν†΅κ³Όν•©λ‹ˆλ‹€.

constκ°€ μ‚¬μš©λ˜μ§€ μ•Šμ„ λ•Œ λˆ„λ½λœ LintλŠ” https://github.com/rust-lang/rust/pull/50110μ—μ„œ μˆ˜μ •λ©λ‹ˆλ‹€.

λ„€, 6λ…„ λ§Œμ— 이 문제λ₯Ό 끝낸 것 κ°™μ•„μš”.μ›ƒμŒ:

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰