プチコン3号(v3.0.2)で文字列配列操作時のメモリリーク対策に失敗した

  • tags
    • petitcom
  • last modified2015-01-16
  • created2015-01-12

注意

以下は プチコン3号 v3.0.2 での話. おそらく次のバージョンではこのバグは修正されていていると思う.

また,結局失敗したので長い割には内容が無い.

現象

SMILEBASIC v3.0.2では文字列配列に対してのPUSH/POPなどの操作でメモリリークするバグがある. (SHIFT/UNSHIFTも同様)

'注意 プチコンを再起動するまでメモリが戻らなくなる
VAR A$[0],T$
WHILE 1
 PUSH A$,"":T$=POP(A$)
 ?FREEMEM
WEND

また関数を用いて文字列配列をすげ替えるような動作でもリークする.

VAR B$[0]
WHILE
 B$=FUNC()
 ?FREEMEM
WEND

DEF FUNC()
 DIM A$[1]:A$[0]=""
 RETURN A$
END

ところで関数を用いた後者の例で,A$[0]=""を消すとリークしていないように見える. 未初期化のB$を代入した場合はリークする.

DEF FUNC1() ' リークしない
 DIM A$[1]
 RETURN A$
END

DEF FUNC2() ' リークする
 DIM A$[1],B$:A$[0]=B$
 RETURN A$
END

以上のことから未初期化の文字列配列には特別な値が入っていて これを使って文字列配列を開放(?)できないかと考えた.

バグ対策PUSH/POP(失敗)

'バグ対策PUSH/POP(失敗)
DEF DISPOSE A$
 VAR T_$[1],I,L=LEN(A$)-1
 FOR I=0 TO L:A$[I]=T_$[0]
END

DEF SAFEPUSH(A$,V$)
 VAR L=LEN(A$)
 VAR B_$[L+1]
 COPY B_$,A$,L:B_$[L]=V$
 DISPOSE A$
 RETURN B_$
END

DEF SAFEPOP(A$)
 VAR L=LEN(A$)-1
 VAR B_$[L]
 COPY B_$,A$,L
 DISPOSE A$
 RETURN B_$
END

結果

上のSAFEPUSH/SAFEPOPは次のような単純な利用の場合はリークしていないようにみえる.

DIM S$[0]
WHILE TRUE
 S$=SAFEPUSH(S$,"A")
 S$=SAFEPUSH(S$)
 ?FREEMEM
WEND

しかし次の様に一定数確保するようにすると,実行するごとにリークするのが確認できる.

DIM I,S$[0]
WHILE TRUE
 FOR I=0 TO 100:S$=SAFEPUSH(S$,"A"):NEXT
 FOR I=0 TO 100:S$=SAFEPUSH(S$):NEXT
 ?FREEMEM
WEND

そんなわけで対策は残念ながら失敗. 次のバージョンアップが待ち遠しい.