hyunsu blog

홈강좌Rust 실무 16편 중 12편째

바이브 코딩 주의점 — 없는 API·옛 문법·없는 버전·가짜 크레이트

목차 · 6
  1. 011. 그럴듯하지만 없는 메서드
  2. 022. 판이 바뀌며 달라진 문법
  3. 033. 폐기된 이름은 경고로만 온다
  4. 044. 없는 버전
  5. 055. 공급망 — 컴파일러가 못 잡는 것
  6. 06실습 — 받아들이기 전 확인 목록

바이브 코딩은 AI 가 쓴 코드를 꼼꼼히 읽지 않고 돌아가면 받아들이는 방식이다. 빠르지만, Rust 에서도 자주 걸리는 함정이 있다. 없는 메서드, 판(edition)이 바뀌며 달라진 문법, 폐기된 이름, 없는 크레이트 버전을 실제 오류로 본다. 컴파일러가 잡지 못하는 공급망 위험은 2025년 crates.io 악성 크레이트 사례와 함께 정리한다.

01 1. 그럴듯하지만 없는 메서드

다른 언어에서는 목록에 바로 sum() 을 부르기도 한다. Rust 에서는 반복자(입문 37편)의 메서드다.

rust
fn main() {
    let scores = vec![72, 85, 90];
    let total: i32 = scores.sum();
    println!("{total}");
}
text
error[E0599]: the method `sum` exists for struct `Vec<{integer}>`, but its trait bounds were not satisfied
 --> src/main.rs:3:29
  |
3 |     let total: i32 = scores.sum();
  |                             ^^^ method cannot be called on `Vec<{integer}>` due to unsatisfied trait bounds
  |
  = note: the following trait bounds were not satisfied:
          `Vec<{integer}>: Iterator`
          which is required by `&mut Vec<{integer}>: Iterator`
          `[{integer}]: Iterator`
          which is required by `&mut [{integer}]: Iterator`

E0599 다. Vec 에 sum 이 있기는 한데 Iterator 여야 쓸 수 있다고 말한다. scores.iter().sum() 으로 고친다. 이런 실수는 컴파일러가 반드시 잡으니 위험하지 않다. 그러니 "컴파일됐다" 를 기본 관문으로 삼는다.

02 2. 판이 바뀌며 달라진 문법

AI 는 학습한 코드의 다수인 예전 판(edition 2021 이전)의 습관으로 쓰기 쉽다. 환경 변수를 바꾸는 set_var 는 2024 판에서 unsafe 함수가 됐다.

rust
use std::env;

fn main() {
    env::set_var("APP_MODE", "test");
    println!("{}", env::var("APP_MODE").unwrap());
}
text
error[E0133]: call to unsafe function `set_var` is unsafe and requires unsafe block
 --> src/main.rs:4:5
  |
4 |     env::set_var("APP_MODE", "test");
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
  |
  = note: consult the function's documentation for information on how to avoid undefined behavior

공식 판 안내서(Edition Guide)는 이유를 여러 스레드가 도는 프로그램에서 환경을 바꾸면 메모리 안전을 깰 수 있어서라고 설명한다. 여기서 위험한 대응은 unsafe { } 로 감싸 오류만 없애는 것이다. 에이전트가 오류를 없애려고 unsafe 를 붙였다면, 그 이유를 꼭 사람이 읽는다. 설정은 환경 변수를 바꾸는 대신 인자로 넘기는 편이 낫다.

03 3. 폐기된 이름은 경고로만 온다

rust
fn main() {
    let input = "   hello";
    println!("[{}]", input.trim_left());
}
text
warning: use of deprecated method `core::str::<impl str>::trim_left`: superseded by `trim_start`
 --> src/main.rs:3:28
  |
3 |     println!("[{}]", input.trim_left());
  |                            ^^^^^^^^^
  |
  = note: `#[warn(deprecated)]` on by default
help: replace the use of the deprecated method
  |
3 -     println!("[{}]", input.trim_left());
3 +     println!("[{}]", input.trim_start());
  |

warning: `trim` (bin "trim") generated 1 warning (run `cargo fix --bin "trim" -p trim` to apply 1 suggestion)

trim_left 는 trim_start 로 바뀌었다(superseded). 경고라서 컴파일은 되고 돌기도 한다. 그래서 "돌아가니까" 로 받아들이면 쌓인다. 11편의 -D warnings 가 이런 것을 막는다.

04 4. 없는 버전

에이전트가 Cargo.toml 에 버전을 지어내기도 한다.

toml
[package]
name = "notes"
version = "0.1.0"
edition = "2024"

[dependencies]
serde = "=1.0.999"
text
    Updating crates.io index
error: failed to select a version for the requirement `serde = "=1.0.999"`
candidate versions found which didn't match: 1.0.229, 1.0.228, 1.0.227, ...
location searched: crates.io index
required by package `notes v0.1.0 (~/projects/notes)`
if you are looking for the prerelease package it needs to be specified explicitly
    serde = { version = "1.0.172-alpha.0" }

cargo 가 그런 버전은 없다며 실제 있는 버전을 보여 준다. 이것도 바로 드러나서 덜 위험하다. 더 위험한 것은 이름이 그럴듯한데 실제로 있는 크레이트다.

05 5. 공급망 — 컴파일러가 못 잡는 것

  • 2025년 9월 crates.io 팀은 악성 크레이트 faster_log 와 async_println 을 지웠다고 공지했다. 인기 로그 크레이트 fast_log 를 비슷한 이름으로 베꼈고, 로그 기능은 그대로 돌면서 로그 파일에서 암호화폐 개인키를 찾아 외부로 보냈다. 내려받기는 각각 7,181번·1,243번이었다.
  • USENIX Security 2025 논문(Spracklen 외)은 코드 생성 모델 16개로 파이썬·자바스크립트 코드 576,000개를 만들어, 추천된 패키지 가운데 존재하지 않는 패키지의 평균 비율이 상용 모델 5.2% 이상·공개 모델 21.7% 라고 밝혔다. 서로 다른 지어낸 이름이 205,474개였다. Rust 를 다룬 연구는 아니지만, 지어낸 이름을 누군가 먼저 등록해 두면 바로 위의 사고가 된다.

이런 코드는 컴파일도 테스트도 잘 통과한다. 그래서 사람이 확인해야 한다.

06 실습 — 받아들이기 전 확인 목록

확인방법
컴파일·린트·테스트cargo fmt --check · cargo clippy --all-targets -- -D warnings · cargo test (11편)
새 크레이트가 들어왔나Cargo.toml 변경을 본다. 이름 철자, crates.io 의 내려받기 수·저장소·최근 갱신(4편)
버전이 고정됐나= 고정 + Cargo.lock 저장(입문 41편)
알려진 취약점RustSec 권고 데이터베이스(cargo audit 도구가 이것을 읽는다)
unsafe·unwrap새로 생겼으면 이유를 읽는다(10편)
테스트가 바뀌었나기대값을 고쳐 통과시킨 것은 아닌지(11편)

AI 는 빠른 첫 판을 주고, Rust 의 컴파일러와 도구는 그 첫 판의 많은 실수를 기계적으로 걸러 준다. 남는 것, 즉 무엇을 들여오고 무엇을 믿을지는 사람이 정한다. 다음 편부터는 웹·API 서버에서 Rust 를 어떻게 쓰는지와 보안을 다룬다.