Cocos2d-x 클라이언트에 버그가 세 개 올라왔다. 마지막 스테이지에서 다음 버튼이 안 눌린다. 아이템이 많으면 목록 끝이 안 보인다. 랭킹 첫 화면에 한 명이 빠진다. 서로 상관없어 보였다.
Table of contents
Open Table of contents
셋 다 같은 모양이었다
첫 번째는 StageClearLayer 의 비교 연산자였다. 마지막 스테이지에서 조건이 거짓이 되어 버튼이 안 나온다.
if (m_currentStage < m_maxStage) { showNextButton(); }
두 번째는 반복 조건에서 하나를 빼고 있어 마지막 항목을 안 그렸다. 세 번째는 시작 인덱스가 1 이라 첫 번째를 건너뛰었다.
for (int i = 0; i < m_items.size() - 1; i++) { drawItem(i); }
for (int i = 1; i < rank.size(); i++) { drawRank(i); }
셋 다 경계에서 하나 어긋나는 것이었다. 증상은 다른데 모양이 같았다.
두 번째는 더 나쁜 것이 숨어 있었다. size() 는 부호 없는 정수다. 빈 목록에서 size() - 1 을 하면 0 이 아니라 아주 큰 값이 된다.
v.size() = 0
v.size() - 1 = 18446744073709551615
아이템이 하나도 없을 때 그 반복문은 안 도는 것이 아니라 끝없이 돈다. drawItem 이 없는 인덱스를 만지다 죽는다. 목록이 빈 InventoryLayer 에서 앱이 죽던 것이 이것이었다. i + 1 < size() 로 바꿨다.
왜 이런 것이 났는지 봤다
SVN 이력을 보니 세 자리 다 처음 만들 때는 맞았다. 나중에 조건이 바뀌면서 어긋났다.
InventoryLayer 는 원래 마지막 항목을 따로 그렸다. 그 코드를 지우면서 반복 조건의 보정을 안 지웠다. RankLayer 는 1 등을 크게 따로 그리다가 그것을 없애면서 시작 인덱스가 남았다. 무언가를 지울 때 그것과 짝인 것을 같이 안 지운 것이다.
같은 모양을 전부 찾았다
같은 형태를 grep 으로 찾으니 세 군데가 나왔다.
$ grep -rn "size() - 1" --include=*.cpp Classes/
그중 하나는 맞는 것이었다. CCSprite 로 구분선을 그리는데 마지막 뒤에는 안 그리려고 쓴 것이다. grep 으로 후보를 모으되 전부 틀렸다고 보면 안 된다. 하나씩 열어 봐야 했다.
경계 확인과 반복문 형태
눈으로 보는 것으로는 계속 놓쳐서 확인하는 자리를 만들었다. CCAssert 로 0 개와 1 개와 2 개와 많을 때를 본다.
layer->setItems(makeItems(0)); CCAssert(layer->drawnCount() == 0, "0개");
layer->setItems(makeItems(1)); CCAssert(layer->drawnCount() == 1, "1개");
하나 어긋나는 것은 0 개와 1 개에서 거의 다 걸린다. COCOS2D_DEBUG 빌드에서만 돌게 뒀다. 많은 경우만 확인하면 안 드러난다.
반복문 형태도 바꿨다. 인덱스를 직접 다루면 처음과 끝을 매번 적어야 해서 어긋난다. CCArray 를 쓰는 자리는 CCARRAY_FOREACH 로 돌게 했다. std::vector 는 iterator 로 돌린다. 그러면 - 1 을 쓸 자리 자체가 없다. 특별히 처리할 것이 있으면 그것만 밖으로 뺐다.
세 건은 처음에 각각 다른 사람이 보고 있었다. 각자 자기 .cpp 만 고쳤으면 같은 것이 다른 자리에 남았을 것이다. 올라온 것을 모아 놓고 보니 같은 모양이 보였다.
정리
- 서로 달라 보이는 증상의 원인이 한 가지 모양일 수 있다
- 경계에서 하나 어긋나는 것은 무언가를 지우면서 짝을 안 지워서 생긴다
- 같은 모양을 검색으로 모으되 전부 틀렸다고 보지 않는다
- 0개와 1개와 2개와 많을 때를 확인한다
- 하나 어긋나는 것은 0개와 1개에서 거의 다 걸린다
size()는 부호가 없다.size() - 1은 빈 목록에서 거대한 값이 된다CCARRAY_FOREACH나iterator로 돌면 그 자리 자체가 없어진다- 올라온 것을 모아 놓고 본다
- 각자 자기 것만 고치면 같은 것이 다른 자리에 남는다