Files
HECO2/doc/펌웨어_정적분석_버그리포트.md
T
jeon 096111e983 feat: 06-17 신규 작업본 반영 (개발사양서/기능검토/승인원/Source 등 추가)
.claude/ 제외(.gitignore 추가). 기존 초기커밋(5a96a69) 위에 신규·수정·이동분 커밋.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 07:54:58 +09:00

10 KiB

HERV 펌웨어 정적분석 버그 리포트

작성일: 2026-06-15 대상: program/User/*.c, *.h (펌웨어 전체) 방식: 영역별 정적분석(읽기 전용). 코드 수정 없음 — 검토용 목록 표기: ✓ = 작성자가 직접 코드 확인 / (분석) = 분석에서 도출(미재확인) / [의심] = 추가 검증 필요


0. 우선순위 요약 (먼저 고칠 것)

# 위치 심각도 한줄 검증
1 My_RJ2.c:617 High switch case 8 break 누락 → 공청3단 세팅이 4단 프리셋 덮어씀
2 My_RJ2.c:400 High Command_request_type = 0; 로 보류비트(HOOD/예약/Homenet래치) 전멸
3 My_bunbaegi.c:869 High 예약시간 offset 오류: [8] 검사하고 값은 [7](풍량)에서 읽음
4 MyControl.c:595 High 필터리셋 조건에 Filter_timer_change 중복(Soja_timer_change 오타) → 소자 리셋 누락 (분석)
5 My_bunbaegi.c:708·898 Med 수신 id(buffer[3]) 범위검증 없이 크기7 배열 인덱싱 → OOB 쓰기 가능 (분석)
6 My_bunbaegi.c:280 Med Light_Bright[6] 만 크기6(형제 배열은 7) → 거실2(id_2=6) 접근 시 OOB
7 My_RJ2.c:110 Med Reservation_process() 주석처리 → 룸컨 예약(Reserve_timer_sec) 카운트다운 안 함

1. 통신 / 프로토콜

My_RJ2.c (룸컨)

  • [High] My_RJ2.c:617 — case 8 break 누락 (fall-through)
    • case 8(공청 3단 VSP) 끝에 break가 없어 case 9(4단)로 흘러감 → 공청 3단 세팅 시 4단 프리셋(Test_Fan*_Air_4_dan)까지 같은 값으로 오염.
    • 제안: case 8 끝에 break; 추가.
  • [High] My_RJ2.c:400 — Command_request_type = 0; 전체 클리어
    • if(Command_request_type & TYPE_SEND_FLAG) 블록에서 = 0;&= ~TYPE_SEND_FLAG;(죽은 코드). SEND_FLAG만 소비해야 하는데 같은 사이클에 set된 TYPE_HOOD_STATE/TYPE_RESERVATION/병합된 Homenet_RJ_Request 비트가 한 번에 사라져 후드·예약 변경이 룸컨에 유실.
    • 비교: line 690~의 같은 패턴은 &= ~TYPE_SEND_FLAG만 함(불일치).
    • 제안: = 0;&= ~TYPE_SEND_FLAG; 로 교체, 필요한 비트만 명시적으로 클리어.
  • [Med] My_RJ2.c:712 — Filter_Reset_Flag |= buffer[7] 마스크 누락
    • EVENT 경로(line 462)는 & 0x01 마스크를 쓰는데 여기선 통째 OR → 상위비트 오염으로 의도치 않은 필터 리셋 가능. 제안: & 0x01 적용.
  • [Med][의심] My_RJ2.c:702-705 — AUTO 수신 시 Fan_Mode 미갱신
    • else 분기에서 AUTO면 Set_Fan_Mode/Fan_Mode를 갱신 안 한 채 line 718 Set_Fan_Mode==Fan_Mode 비교 → TYPE_FAN_SPEED 비트가 옛값으로 클리어/유지되어 풍량 명령 어긋남 가능. EVENT 분기(414-415)와 기준 통일 검토.

My_bunbaegi.c (분배기/디퓨저 마스터)

  • [High] My_bunbaegi.c:869 — 예약시간 byte offset 오류
    • if(Rx_bunbaegi_buffer[8] & 0x80){ Set_Reserve_timer_sec = (uint32_t)(Rx_bunbaegi_buffer[7] & 0x7f)*3600; } — 요청비트는 [8]에서 보고 값은 [7](풍량 바이트)에서 읽음 → 예약시간이 풍량값으로 들어감. 제안: [8]에서 읽기.
  • [Med] My_bunbaegi.c:708·898 (Diffuser/EachRoomCon parsing) — 수신 id 범위검증 없음 (분석)
    • id = Rx_bunbaegi_buffer[3];SEN66_*[id], Diffuser_Power[id] 등 크기7 배열에 상한 체크 없이 인덱싱. 오염된 id(≥7)면 OOB 쓰기로 전역 손상. 제안: if(id < 7) 가드.
  • [Med] My_bunbaegi.c:183/191 — RoomCon Packet_Length가 절대 29가 안 됨 (분석)
    • case 3에서 무조건 39, case 4 RoomCon 분기도 39(주석은 //29byte). → case 28의 29B 완료처리 분기가 죽은 코드. 29B 응답 파싱 불가. 제안: 의도대로 case 4에서 Packet_Length = 29;.
  • [Low] My_bunbaegi.c:813 — VSP 저장 트리거가 case 3(BYPASS)에만 존재 (분석)
    • VEN/AIR VSP를 룸컨에서 바꾸면 EEP_Save_Flag 미설정 → 재부팅 후 유실 가능. 제안: case 1/2에도 동일 저장 조건.

My_Homenet.c (PC 대시보드)

  • [Low/설계확인] My_Homenet.c:366 — CTRL_VSP u16→u8 truncation
    • (uint8_t)(((uint16_t)pl[2]<<8)|pl[3]) 는 상위바이트를 시프트 후 캐스팅으로 버려 사실상 pl[3](하위)만 사용. VSP가 0~255라 실사용은 무해하나, 의도 명확화를 위해 pl[3]만 쓰는 게 안전. (확정 손상 아님)
  • [Low/의심] My_Homenet.c:410 — hn_apply_cmd(cmd, pl, HN_DATA_LEN) 로 len 항상 240 (분석)
    • 모든 if(len >= N) 검증이 무조건 통과 → 짧은 명령 의미검증이 사실상 무력. 고정 244B 구조라 오버런은 없음. 동작 영향 낮음.

My_Hood.c (후드)

  • [Med] My_Hood.c:64 — 헤더 불일치 바이트를 버퍼에 기록 (분석)
    • case 1에서 0x11 불일치 시 Rx_hood_Pos=0 후에도 Rx_Hood_Buff[Pos++]=data 실행 → 잘못된 바이트가 buffer[0]에 들어가 프레임 한 칸 밀림. 제안: 불일치 시 Pos=0; break; 로 즉시 반환.

2. 시스템 / 전원 / 예약

main.c

  • [Low] main.c:116-119 — Process_10ms 재장전값 3000, 본문 비어있음(데드/오타)
    • Process_5ms/Process_10ms 블록 모두 카운터만 재장전하고 작업 없음(no-op). 동작 영향은 없으나 =3000은 명백한 leftover. 제안: 블록 제거 또는 의도값 복원.

My_system.c

  • [Med] My_system.c (예약 카운터 이원화) — Reserve_Remain_Sec(HomeNet) vs Reserve_timer_sec(룸컨)
    • main.c 1초 루프는 Reserve_Remain_Sec만 감산. 룸컨용 Reserve_timer_sec를 감산하는 Reservation_process()My_RJ2.c:110에서 주석처리 → 룸컨이 설정한 예약은 카운트다운/전원OFF가 안 됨. 제안: 카운터 단일화 또는 Reservation_process() 호출 복원.
  • [Med] My_system.c:728 부근 sensor_level()T[i] - db unsigned 언더플로 (분석)
    • uint16_t 임계-데드밴드. 대시보드로 임계를 작게 설정하면 래핑되어 단계판정 폭주. 정상 사양값에선 미발생. 제안: 뺄셈 전 T>=db 가드 또는 signed 후 0 클램프.
  • [Med] My_system.c (Air_Quality_color_process 선두 return(0)) — 본문 도달불가(데드코드) (분석)
    • 매초 호출되나 색상/quality 계산 전체가 실행 안 됨. 의도된 비활성화인지 확인 필요(색상은 Air_Quality_damper_process가 별도 세팅).

3. 모터 / 댐퍼 / PWM (MyMotor.c)

  • [Med] MyMotor.c:893·897 — 팬 PWM 보정항 정수 오버플로/truncation (분석)
    • BLDC_SPEED_TABLE[..]*Volum_value/1000 이 int로 먼저 계산 → 큰 값/음수 Volum에서 오버플로·정밀손실. 제안: float 우선 캐스팅 또는 Volum 범위 클램프.
  • [Med] MyMotor.c — BLDC_SPEED_TABLE[Fan_Speed](크기100), Target_Step_Count[damper_num](크기7) 인덱스 미검증 (분석)
    • 정상 VSP/모드값에선 안전하나 방어 없음. Fan_Speed≥100 또는 damper_num≥7 시 OOB. 제안: 접근 전 클램프/가드.
  • [Med][의심] MyMotor.c:1011 외 — Step_Status != 0x3F 수렴 대기 무한블록 가능
    • 특정 타이밍에 6댐퍼 전부 0x3F 미도달 시 후속(팬 목표갱신) 진입 불가. 타임아웃/완료플래그 보강 검토.
  • [Low][의심] MyMotor.c:962-979 — Vsp_Select if-else 체인 공백구간
    • 1015, 0x210x24 등 미정의 값은 어느 분기에도 안 걸려 Target/Damper 미설정. 정상 범위면 무해. default 처리 검토.

4. 제어 / EEPROM (MyControl.c)

  • [High] MyControl.c:595 — 필터리셋 조건 Filter_timer_change 중복(오타) (분석)
    • if((Filter_timer_clean==0)&&(Filter_timer_change==0)&&(Filter_timer_change==0)) 세 번째는 Soja_timer_change==0 이어야 함 → 소자 청소/교체 카운터 리셋 누락. 제안: 세 번째를 Soja_timer_change로 교정.
  • [Med] MyControl.c:659 — Pre_Mode_Control 부분쓰기 루프 상한이 127 (분석)
    • 정전복귀 3바이트(4042)만 필요한데 i<EEP_SIZE(127)까지 순회 → 히스테리시스 영역(43127)을 RAM 미러로 재기록. 동기화 타이밍에 따라 임계 롤백 위험 + 불필요 스캔. 제안: 상한을 42로 제한.
  • [Med][의심] MyControl.c:531·536 — Volum1/2_value 변환식이 주석범위(-100100) 초과(+175-75)
    • 다운스트림에서 -100~100 가정 시 오버레인지. 계수/오프셋 재검토 또는 결과 클램프.

5. Light_Bright 배열 불일치 (교차 이슈)

  • [Med] My_bunbaegi.c:280 / My_define.h:495 — Light_Bright[6] 만 크기6
    • 형제 각실배열(Diffuser_*, SEN66_* 등)은 모두 [7](인덱스 06, 거실2=6). Light_Bright[6](05). My_bunbaegi.c:622/645 Light_Bright[id_2] 에서 id_2=6(거실2) 도달 시 OOB 읽기 → 인접 전역 오염. 제안: Light_Bright[7] 로 통일.

6. 점검했으나 "버그 아님" (오판 방지 기록)

  • MODE_ 중복정의(My_define.h 265-268 / 275-278)*: #if((SPEC_MODE_INFO&0x0F)==0x03||==0x06) 가드. 현재 SPEC_MODE_INFO=0x16(&0x0F=0x06) → 첫 블록만 컴파일(VENT=0/AUTO=1/AIRCLEAN=2/BYPASS=3). 충돌 아님. 단 사양값 변경 시 BYPASS/AIRCLEAN(2↔3) 매핑이 바뀌는 잠재위험 → 프로토콜 코드값 고정 가정과 대조 필요.
  • CRC 계산범위/바이트순서(My_bunbaegi, My_Homenet): 송수신 내부 일관(27B/37B 데이터 + 2B CRC). CRC16()이 표준MODBUS 바이트스왑값을 반환하고 [n]=icrc>>8 배치로 상쇄 → 와이어는 표준 리틀엔디안. 정상. (시뮬레이터는 lo-first로 일치시킴)
  • CTRL_RESERVE 곱셈(My_Homenet.c:385): pl[0]*3600 int 승격으로 최대 28800 정상.
  • EEPROM 인덱스/페이지 경계(MyControl.c): 히스테리시스/임계 영역 최댓값 127(=EEP_SIZE-1), 페이지(128B) 침범 없음. 서명 0x55AA55AA + 별도 유효성 마커 검증 정상.
  • pwm_duty10000.c: 룩업테이블이 아니라 표준 Nuvoton PWM 드라이버. 범위초과 없음.

참고

  • 본 리포트는 분석만 수행했고 소스는 수정하지 않았습니다.
  • (분석) 표기 항목은 영역별 분석에서 도출됐고 작성자 재확인 전입니다. 수정 착수 전 해당 라인을 함께 열어 확정하는 것을 권장합니다.
  • 우선순위 1~4(High)는 동작 증상으로 이어질 가능성이 가장 높습니다.