あるファイルサーバをNetBSD 10から11_RC5にしたら、samba (smbd, nmbd) があぼ~ん abort で core 吐いて死ぬ。でも、先に11系にした他のサーバでは動いてる。
gdbにcoreを食わせたところ、isspaceで死んでる。
samba-4.24.4/lib/util/util_str_common.c:
/* sync the strings on first non-whitespace */
while (1) {
while (isspace((int)*psz1))
psz1++;
while (isspace((int)*psz2))
psz2++;
そのときpsz1という変数名に何が入っていたかというと、smb.conf のセクションになってる共有名。でまあ、それが日本語 (UTF-8) なんだけど、int にキャストしてしまっているので負の値が渡っていたと。(他では日本語の共有名とか使ってないから動いてたんだな。)
じゃあなんで10では大丈夫だったかというと、
--- netbsd-10/src/lib/libc/gen/isctype.c
+++ netbsd-11/src/lib/libc/gen/isctype.c
…
+static int __noinline
+ctype_nasaldemon(const char *func, int c)
+{
+ char buf[128];
+
+ snprintf_ss(buf, sizeof(buf), "ctype(3) %s: invalid input: %d\n", func,
+ c);
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ if (allow_ctype_abuse())
+ return -1;
+ abort();
+}
+
+#define CTYPE_CHECK(c) do \
+{ \
+ if (__predict_false(((c) != EOF && (c) < 0) || (c) > UCHAR_MAX)) \
+ return ctype_nasaldemon(__func__, c); \
+} while (0)
#define _ISCTYPE_FUNC(name, bit) \
int \
is##name(int c) \
{ \
+ CTYPE_CHECK(c); \
return (int)_ctype_tab_[c + 1] & (bit); \
} \
int \
is##name ## _l(int c, locale_t loc) \
{ \
+ CTYPE_CHECK(c); \
return (int)((_RUNE_LOCALE(loc)->rl_ctype_tab[c + 1]) & (bit)); \
}
is##name がその後のマクロで isspace とかになるんだけど、11で CTYPE_CHECK というのが追加されている(10にはない)。んで、その中で範囲チェックをして、EOFでない負の数なので ctype_nasaldemon の abort(); に辿り着くと。
え、10のときは負の方向に突き抜けてたんかい。
対処
上のソースで allow_ctype_abuse() というのがあるが、環境変数 LIBC_ALLOWCTYPEABUSE というのをセットしておくと abort は回避できるらしい。
まっとうな直し方は、
--- lib/util/util_str_common.c.orig 2026-01-21 00:42:54.186816700 +0900
+++ lib/util/util_str_common.c 2026-07-02 17:40:22.843239543 +0900
@@ -41,9 +41,9 @@
/* sync the strings on first non-whitespace */
while (1) {
- while (isspace((int)*psz1))
+ while (isspace((unsigned char)*psz1))
psz1++;
- while (isspace((int)*psz2))
+ while (isspace((unsigned char)*psz2))
psz2++;
/*
……でしょうかね。