The Man Who Fell From The Wrong Side Of The Sky:2013年11月21日分

[最新版] [一覧] [前月] [今月] [翌月]

2013/11/21(Thu)

[Operating System Source Code Secrets Volume 334][な阪関無] sys/cdefs.hとは何ですか? (その8)

@ 訂正記事を書けば免許証を返していただけるんですね?

4.4BSDでの変更箇所をNetBSDがいつ取り込んだのかについて、 曽田さんから おいゴラァ修正しろよ!あくしろよご指摘頂きました。

@tnozaki http://t.co/XOYgJP99QV ですが、4.4のコードは、Liteリリース前から取り込み始めてました(作業完了は勿論リリース後)。cgdがバークレーにいた関係で、NetBSD→4.4Lite方向のフィードバックもあった模様です。

— SODA Noriyuki (@n_soda) November 21, 2013

@tnozaki 訴訟がらみでリポジトリから履歴があらかた消されてて分かりづらいですが、例えば1993年9月14日には既にmagnumブランチへのコミットが: http://t.co/I176Ce12uf これは4.4のリリース後、Liteのリリース前の時期です。

— SODA Noriyuki (@n_soda) November 21, 2013

文中のcgdとは cgd(4)の事で CryptoGraphic Disk driver がしゃべった!?という超常現象です。

ではなくChris G. Demetriou <cgd AT NetBSD DOT org> 氏の事を指します。ちなみに 元coreです、そういえば長いこと姿見てない気がする。

あと Mutt開発者tamoさんからも 誤字のご指摘ありがとうございました(野獣の眼光)、やべぇよ…やべぇよ…

@ 前回まで

NetBSD1.1までの変更、__warn_referencesマクロの機能について学びました、今回はNetBSD1.1〜1.3で入った変更です。

そういえば今のNetBSDのバージョン命名規則とこの時期って違うんですが若い人って知らなかったりして説明必要ですかね、それとも若いNetBSDerとか 非実在青少年ですかそうですか。

@ __weak_references() マクロ

rev1.13で__weak_referencesという名で導入されたマクロですが、このマクロは変身する度に実装が混乱し、その変身をあと2回も俺は残している!

過去記事 ( その1) ( その2) で__weak_alias マクロについてはあらかた説明済ですが、__weak_references/__indr_referencesも合わせてまた回を改めて説明する予定です。

@ __kprintf_attribute__() マクロ (削除済)

gccは関数にformat属性というものを付けることが出来ます、これはprintfっぽい関数のコンパイル時にフォーマット文字列をデリケートにバリデートしてくれる優しい機能です。

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>

void kprintf(const char *, ...) __attribute__((format(printf, 1, 2)));

void
kprintf(const char *a, ...)
{
        va_list ap;
        va_start(ap, a);
        vprintf(a, ap);
        va_end(ap);
}

int
main(void)
{
        kprintf("%b");
        exit(EXIT_SUCCESS);
}

ところがkprintf(9)ではprintf(3)には存在しない変換指定子「%b」をサポートしているので、こいつがエラーと判断されてしまうのでこの属性を付けられなかったのよね。 上記のコードをコンパイルすると警告がでます。

$ gcc -Wall test.c
test.c: In function 'main':
test.c:19:2: warning: unknown conversion type character 'b' in format [-Wformat=]
  kprintf("%b");
  ^

だもんげ、カッとなってgccを 改造した、今は反省している。

...
  41 /* Format kinds */
  42 #define F_USER  0x1             /* Format used in user-land printf/scanf */
  43 #define F_KERN  0x2             /* Format used in kprintf/scanf etc. */
...
  47 #define FORMAT_CONTEXT(p) (((p)->format_kind & (F_USER|F_KERN)))
...
 557             if (TREE_CODE (format_type) == IDENTIFIER_NODE
 558                 && (!strcmp (IDENTIFIER_POINTER (format_type), "printf")
 559                     || !strcmp (IDENTIFIER_POINTER (format_type),
 560                                 "__printf__")))
 561               format_kind = F_USER;
 562             else if (TREE_CODE (format_type) == IDENTIFIER_NODE
 563                      && (!strcmp (IDENTIFIER_POINTER (format_type), "kprintf")
 564                          || !strcmp (IDENTIFIER_POINTER (format_type),
 565                                      "__kprintf__")))
 566               format_kind = F_KERN;
...
 692 typedef struct {
 693   char *format_chars;
 694   int format_kind;
...
 712 } format_char_info;
 713
 714 static format_char_info print_char_table[] = {
 715   { "di",       F_USER|F_KERN,  0, T_I, T_I,    T_L,    T_LL,   T_LL,   "-wp0 +"        },
 716   { "oxX",      F_USER|F_KERN,  0, T_UI,T_UI,   T_UL,   T_ULL,  T_ULL,  "-wp0#"         },
 717   { "u",        F_USER|F_KERN,  0, T_UI,T_UI,   T_UL,   T_ULL,  T_ULL,  "-wp0"          },
...
 727   { "n",        F_USER,         1, T_I, T_S,    T_L,    T_LL,   NULL,   ""              },
 728 /* Kernel bitmap formatting */
 729   { "b",        F_KERN,         1, T_C, NULL,   NULL,   NULL,   NULL,   ""              },
...
1046           else if ((FORMAT_CONTEXT(info) & F_KERN) != 0)
...

564行目で__attribute__((format))の引数にkprintf/__kprintf__を追加しています。

んで

フラグをセットしとります。

んで714行目フォーマット文字列中の変換指定子のチェック用定義テーブルprint_char_tableで

↑ビットを立ててとります。

最後に1046行目でformat_kindとprint_char_table.format_kindを比較しF_KERNビットが立ってれば、kprintf用のチェックを実施します。

前述の%bには729行目でF_KERNだけが立ってるので、kprintf(9)でのみサポートされとるちゅーことですね。

ちゅーことでさっきのコードはこう書き換えることで%bについてもgccはエラーチェックしてくれるようになったと。

void kprintf(const char *, ...) __attribute__((format(kprintf, 1, 2)));

@ 現在の kprintf(9)

現在は %b に関しては bitmask_snprintf(9)を使って文字列に変換したうえで %s 使えとなっとりますので、userlandと同様の__attribute__((format(printf, m, n)))が使えます、よってこのマクロも改造も過去の話です。

ちなみにkprintf(9)の マニュアルにbitmask_snprintf(9)のマニュアル見ろとおもいっくそありますが、そんなものは無い模様。

the typical NetBSD style we did not document/advertise it.

平常運転です。

つーか今調べたらbitmask_snprintf(9)もobsoleteで、libutilの snprintb(3)使えじゃねーか。

あと余談ですがtech-kernelあたりではtime_tをprintf(9)で表示しようにも適切な変換指定子無いよね、って文句が時々出てきます。userlandであれば strftime(3)で文字列に変換できるわけですが、src/sys/kernelにはstrfrime(9)は無いからのう。

現時点では

	time_t time;

	printf("%"PRIdMAX"\n", (intmax_t)time);

で逃げるかですが、libsaの場合 subr_prf.cがLIBSA_PRINTF_LONGLONG_SUPPORT抜きだったりするとアカンですやな。

@ 次回予告


[ホームへ] [ページトップへ]