XSでCの文字列操作関数を使用するべきでない理由
またはRe: PerlとC言語の型に対応する値への相互変換
XSでCの文字列操作関数の使用はなるべく避けるべきです。Cの文字列操作関数は危険で使いにくいものです。その代わりに、Perlが提供する安全で使いやすいSV APIを使ったほうが余計なことを考えずに済みます。
まずC言語でプログラミングする際の一般論として、strcat()やsprintf()などの文字列長を制御できない関数を使用するべきではない、というものがあります。これらの関数を使用して安全なプログラミングをするのは非常に困難であり、代わりにstrncat()やstrlcat()、あるいはsnprintf()といった文字列長を制御できる関数を使うべきです。
またPerl/XSに関して言うならば、そもそもCの文字列操作関数を使う必要はほとんどありません*1。char*の代わりにSV*を使うようにし、なるべくPerl API で文字列を操作するようにすれば、バッファオーバーランやメモリリーク*2といったありがちなバグを簡単に避けることができるからです。
Perl APIとCの文字列操作の対応はperlclibに載っています。文字列部分だけ引用すると以下のようになります。
Most of the time, though, you'll want to be dealing with SVs internally instead of raw "char *" strings: strlen(s) sv_len(sv) strcpy(dt, src) sv_setpv(sv, s) strncpy(dt, src, n) sv_setpvn(sv, s, n) strcat(dt, src) sv_catpv(sv, s) strncat(dt, src) sv_catpvn(sv, s) sprintf(s, fmt, ...) sv_setpvf(sv, fmt, ...) Note also the existence of "sv_catpvf" and "sv_vcatpvfn", combining concatenation with formatting.
この中でも特にsv_setpvf()とsv_catpvf()は強力で、バッファの確保をまったく気にしなくていい分snprintf()を使うよりずっと安全で簡単です。また、Perlのsprintf()に相当するnewSVpvf()もよく使います。これらはたとえば以下のように使います。
SV* const sv = sv_2mortal(newSVpvf("[%d]", 42)); # Perlの"[42]"を作成 sv_setpvf(sv, "<%s>", "foo"); # svは"<foo>" sv_catpvf(sv, "<%s>", "bar"); # svは"<foo><bar>" /* svはスコープの終わりで解放されるので、その行方を気にする必要はない */
もちろんこれらのPerl APIを使用するとそのコードはPerlでしか使えないものになりますが、Perlのためのモジュールを書くならばPerlからしか使えないのは特にデメリットではありません。
*1:たとえば実際にXslateでは、
*2:XSで作成するSVは基本的にmortalにするという原則を貫けば、ほとんどのメモリリークは避けられます。参考:XSでメモリークを避けるたった一つの方法 - Islands in the byte stream