LGES-OC5-PtoP-Welder/Doc/인수인계/260907_NRE_크래시_위험구간_점검.md
NohDoyeon241104 a3238cc2d6 docs: 인수인계 산출물 일괄 커밋 (260903~260916)
그동안 미추적으로 쌓여 있던 인수인계 문서를 정리해 올린다.

260903 Door 인터락 현장검증 가이드 / 파워캘 3000W 오적용 환산

260907 Arc 출사 파라미터 시각화 / LaserFrequency 단위계통 / NRE 위험구간 점검 / 레시피화면 사용설명서

260915 레시피화면 작업매뉴얼

260916 PTOP 프로그램 사용설명서 / 자동운전 전환 사전점검 현장용

작업 중 임시본(_backup)은 제외했다.
2026-09-16 17:10:50 +09:00

7.9 KiB

NRE / 크래시 위험 구간 점검

  • 작성 : 2026-09-07
  • 계기 : 출사 미지원 객체(Ellipse/Rectangle/Roi) NRE 방어(ISSUE-260907-01) 적용 후, 같은 유형이 더 있는지 전수 확인 요청.
  • 성격 : 점검 목록 전용. 소스 미수정. 현장 검증 미실시.
  • 표기 : 🟩 소스 확인 / 🟦 현장 기록 / 🟨 미확보·판정 불가

점검 범위와 한계

구분 내용
포함 Machines/ILSOS_PrismaticRD_PTOP/**, WeldingComponents/WeldingCommon/Sequences/**
제외 AuroraVision, LASA GUI(Canvas·DrawTools), AuroraDevices 하위 대부분, Aurora 프레임워크
방법 패턴 검색(FirstOrDefault/First()/[0]/as/인덱서) 후 해당 라인 전후 확인
한계 정적 분석. 런타임 재현·디버깅 없음. 제외 범위에 같은 유형이 더 있을 수 있음

0. 선행 확인 — 예외가 실제로 프로그램을 종료시키는가

🟩 우리 소스에 전역 예외 핸들러가 없습니다. DispatcherUnhandledException / AppDomain.CurrentDomain.UnhandledException / UnobservedTaskException / SetUnhandledExceptionMode 검색 결과 0건.

🟩 ILSOS_PrismaticRD_PTOP.csproj → OutputType=library. 즉 실행 주체는 Aurora.exe 이고 저장소에 소스가 없습니다.

🟨 따라서 아래 항목이 실제로 프로세스를 종료시키는지는 판정할 수 없습니다.

  • Aurora.exe 가 전역 핸들러를 걸어 두었는지 미확인
  • Aurora SequenceBuilder 가 노드 실행을 try/catch 로 감싸는지 미확인 (sb.OnForceError(...) 훅이 존재하므로 잡을 가능성은 있음)

이 문서는 "NRE 가 발생할 수 있는 지점" 목록입니다. "여기서 프로그램이 죽는다" 로 읽지 마십시오. 종료 여부는 별도 확인 필요.


A. 널 체크 없이 즉시 역참조 — 위험도 최상

A-1. SeqComponentTeachingRun.cs:456-459 🟩

var power = Status.GetProcessingWeldingData().UploadProcessDatas
              .Where(data => data.DataName == $"Power_{SlotNo}_{_SequenceSetting.LastPageNo}")
              .FirstOrDefault();
power.Value = ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower1
            + ScannerCanvasUserCtrl.ScannerParams[paramIndex].LaserPower2;   // ← power == null 이면 NRE

var velocity = ...Where(data => data.DataName == $"Velocity_{SlotNo}_{...}").FirstOrDefault();
velocity.Value = ScannerCanvasUserCtrl.ScannerParams[paramIndex].MarkSpeed;  // ← 동일
  • DataName 을 SlotNo + LastPageNo 로 문자열 조합해 찾습니다.
  • 그 조합이 UploadProcessDatas 에 없으면 FirstOrDefault() 가 null 을 반환합니다.
  • 페이지 수가 늘거나 슬롯 번호 체계가 바뀌면 즉시 발생합니다.
  • 실제 운전 경로(Manual 티칭런)라 재현 가능성이 목록 중 가장 높습니다.

A-2. SeqEventQTest.cs:142-145 🟩 — 3중 위험

FovInfo _fovInfo = VisionRecipeManager.GetFovInfos().FirstOrDefault();
_PatternAgent = FovPatternAgentManager.GetAgent(_fovInfo.ToSubSysInfo());  // ① _fovInfo null → NRE
List<PatternInfo> patterns = _PatternAgent.GetMainPatterns(_fovInfo);      // ② agent null → NRE
_PatternInfo = patterns[0];                                                // ③ 빈 리스트 → IndexOutOfRange

A-3. SeqAutoRunPrismatic.cs:1101-1104 🟩

A-2 와 동일 패턴 + _Patterns[_InitParam.VisionRecipeNo] 인덱스 무검증.

🟩 참고 — 올바른 패턴이 같은 파일에 이미 있습니다. SeqAutoRunPrismatic.cs:743-745 는 _PatternResult?.Results?.FirstOrDefault() 로 널 조건 연산자를 쓰고 이후 if (baseResult != null) 까지 확인합니다. A-2 · A-3 만 이 방어가 빠져 있습니다.


B. as 캐스팅 결과를 가드 없이 보관 — 지연 발화형

캐스팅 실패 또는 키 부재 시 조용히 null 이 되고, 한참 뒤 그 필드를 사용하는 시점에 터집니다. 발생 위치와 원인 위치가 달라 추적이 어렵습니다.

위치 대상 🟩
SeqAutoRunPTOP.cs:291 _SystemParameter 🟩
Views/Main/UCMainAutoRunViewModel.cs:95-97 _SystemParameter, _Scanner, _Plc 🟩
Views/Main/UCMainAutoRunViewModel.cs:472, 505 _SystemParameter 재대입 🟩
SeqTestRun.cs:472 _IOLaser 🟩
SeqComponentTeachingRun.cs:179 _SequenceSetting 🟩
Monitoring/SeqStatusMonitor.cs:60 _SequenceSetting 🟩
SeqAutoRunPrismatic.cs:1050 SystemSetting 🟩
EquipmentSetup.cs:90, 199, 240, 342 EquipmentInfo 🟩
EquipmentSetup.cs:129, 133 IODevice, PLCControllerPTOP 🟩
Recipes/RMSHandlerForPTOP.cs:52-53 _plc, _RmsSetting 🟩

대부분 초기화 구간이라 정상 구성에서는 성공합니다. 위험은 "설정 키 이름 변경 / 디바이스 등록 누락 / 타입 교체" 시 즉시 실패하지 않는다는 점입니다.

🟩 예외 — 이미 방어된 곳 : SeqAutoRunPTOP.cs:1140, 1252 의 LaserInterlockSetting 은 LaserAngleOffsetSelector.Select() 안에서 setting != null 삼항 처리로 방어됩니다.


C. 인덱스 무검증 — NRE 는 아니나 동일하게 종료 요인

위치 위험 🟩
SeqUploadWeldingList.cs:206 SelectedDrawObjectList[0] — 빈 리스트 🟩
SeqUploadWeldingList.cs:207-209 ScannerParams[ScannerParamID - 1] — ID 가 0 이면 인덱스 -1 🟩
SeqUploadWeldingList.cs:474, 617-631, 719, 1006, 1052, 1152, 1204, 1404, 1605 ScannerParams[obj.ScannerParamNo] 범위 무검증 (배열은 128개 고정 생성) 🟩
SeqWaitWeldOrChangePage.cs:194-195 ScannerParams[paramIndex] 🟩
SeqTestRun.cs:237-238 ScannerParams[paramIndex] 🟩
SeqComponentTeachingRun.cs:457-465 ScannerParams[paramIndex] 🟩
SeqAutoRunPrismatic.cs:1104 _Patterns[VisionRecipeNo] 🟩

SeqUploadWeldingList.cs:206-209 주의 — 2026-09-07 적용한 예외처리는 FuncLoadDrawObjectScannerParamSelected() 쪽이라 이 경로는 여전히 무방비입니다.


D. 예외는 안 나지만 값이 오염되는 것 (참고)

double 나눗셈이라 예외 대신 Infinity/NaN 이 조용히 흘러갑니다.

위치 내용
ScannerRTC6.cs:775 · ScannerRTC5.cs:773 32.0 / periodHz — periodHz == 0 이면 Infinity → (uint) 캐스팅은 정의되지 않은 동작
SeqUploadWeldingList.cs:1313-1316 ArcRampingInterval == 0 시 동일

상세 : 260907_LaserFrequency_단위계통_분석.md


우선순위 제안

순위 항목 근거
1 A-1 실제 운전 경로(Manual 티칭런) + 조합 문자열 탐색이라 재현 가능성 최상
2 C 의 SeqUploadWeldingList.cs:206-209 이번 예외처리가 커버하지 못한 인접 경로
3 A-2 / A-3 비전 경로. Vision 미사용이면 후순위
4 B 개별 수정보다 초기화 구간 일괄 널 가드 + 알람이 적절
— 선행 Aurora.exe / SequenceBuilder 의 예외 처리 정책 확인. 이게 정해져야 "가드 후 어떻게 할지"(스킵 / 알람 / 시퀀스 중단)가 결정됨

조치 시 주의

  • 조용히 스킵하면 안 되는 경우가 있습니다. A-1 은 공정 데이터 상신 실패를 뜻하므로, 널이면 로그만 남기고 넘어가면 데이터 누락이 은폐됩니다. 알람 여부를 함께 정해야 합니다.
  • 반대로 이번 ISSUE-260907-01 처럼 원래도 동작하지 않던 경로는 스킵이 맞습니다.
  • 즉 "널이면 무조건 return" 을 일괄 적용하지 마십시오. 항목마다 판단이 다릅니다.

변경 이력

일자 내용 비고
2026-09-07 최초 작성. PTOP + WeldingCommon Sequences 범위 점검 소스 미수정