プチコン3号(v3.0.2)で文字列配列操作時のメモリリーク対策に失敗した
- tags
- 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
そんなわけで対策は残念ながら失敗. 次のバージョンアップが待ち遠しい.