🚰 자원 해제 누락 시뮬레이터 KISA A-5 · 부적절한 자원 해제

요청 핸들러가 호출마다 파일/소켓을 열지만 오류 경로에서 닫지 않습니다. 열린 핸들이 쌓여 OS의 파일 디스크립터(FD) 한계에 도달하면 서비스가 더 이상 연결을 받지 못하고 죽습니다.

① 취약한 핸들러: finally 없는 open() VULNERABLE

각 요청은 디스크립터를 열고, 처리가 실패하면 조기 반환합니다. close()는 작업 뒤에 있어 오류 경로는 이를 건너뜁니다 — 디스크립터가 영영 누수됩니다.
열린 파일 디스크립터0 / 64

② 안전한 핸들러: try-with-resources / finally / RAII SECURE

자원을 스코프에 묶습니다. 요청이 성공하든 예외가 나든, 언어가 모든 종료 경로에서 close() 실행을 보장합니다. 열린 FD 미터가 평평하게 유지됩니다.
열린 파일 디스크립터0 / 64

③ 취약 vs 안전 코드

VULNERABLE — Java
// close()가 정상 경로에만 있음 → 예외 시 누수
void handle(Path p){
    InputStream in = Files.newInputStream(p); // open FD
    process(in);          // ← 예외 발생 시
    in.close();           //   이 줄에 도달 못 함 → 누수
}
VULNERABLE — C
int handle(const char *path){
    FILE *f = fopen(path, "r");      // open FD
    char *buf = malloc(4096);
    if(!buf) return -1;              // ← f 누수!
    if(parse(f, buf) < 0) return -1; // ← f, buf 누수!
    free(buf); fclose(f);
    return 0;
}
SECURE — Java (try-with-resources)
void handle(Path p){
    try(InputStream in = Files.newInputStream(p)){
        process(in);      // 예외가 나도
    }                     // close() 자동 보장
}
SECURE — C (goto cleanup)
int handle(const char *path){
    FILE *f = NULL; char *buf = NULL; int rc = -1;
    f = fopen(path, "r");      if(!f)   goto out;
    buf = malloc(4096);        if(!buf) goto out;
    if(parse(f, buf) < 0)              goto out;
    rc = 0;
out:
    free(buf);                 // NULL-safe
    if(f) fclose(f);           // 단일 해제 지점
    return rc;
}
방어 핵심: 모든 자원을 해제를 보장하는 스코프에 묶기 — try-with-resources / using / defer / RAII · C는 단일 goto out 종료점으로 해제를 일원화 · close()를 성공 경로에만 두지 말 것 · 열린 FD/핸들 수를 조기경보 지표로 모니터링.
⚠️ 교육용 시뮬레이션입니다. 파일 디스크립터·미터·FD 한계는 모두 mock JS 값이며 실제 파일·소켓·시스템 자원을 열지 않습니다.