2016-04-23

Ubuntu 16.04にアップグレードした

Ubuntu 16.04にアップグレードした。今回はかなり問題だらけだった。

まず、アップグレードが正常に終わらなかった。古いパッケージを削除する途中で、hicolor-icon-themeのインストールスクリプトが正常に終了しなかったとのメッセージが表示された。同じ問題が報告されているようだ。

Bug #1571139 “package hicolor-icon-theme 0.15-0ubuntu1 failed to...” : Bugs : hicolor-icon-theme package : Ubuntu

他にも、Localesのインストールスクリプトが正常に終了しなかったというメッセージも表示された。

そして、"E: mkinitramfs failure cpio 141 gzip 1"と表示されたまま画面が完全に固まってしまった。入力を一切受け付けず、端末に切り替えることもできなければ、SysRqもきかない。30分ほど待っても何も起こらないので、仕方なく電源を落とすことにした。

さて、ブートしてみるとGrub2のシェルが表示される。さて、ブートローダーの問題なのだろうか。

とりあえずUbuntu 16.04のISOを落としてブータブルUSBメモリを作成してブートしてみる。あっさりとブートできた。どうやらLive USBではなくて普通にUSBメモリのブートローダーだけを使ってラップトップにインストールしたUbuntuが起動したらしい。ログイン画面は16.04になっている。

それではgrubのインストールだけやり直せばいいのだろうか。とりあえず様子を見てみようとGUIのアップデートプログラムを起動してみたところ、何やら大量のパッケージを確認もなくアップデートして再起動を促された。はて、まだ終わっていなかったのだろうか。

再起動してみるとこれまた普通に使える。古いパッケージ、特に古いLinuxカーネルのパッケージが大量に残っているので、apt-get autoremoveで除去した。

さて、今回はGCCが5.3、Clangが3.8になっている。ただし、libc++とlibc++abiに問題があるようだ。まず、libc++abi-devは、/usr/include/libcxxabi/下にインストールされるのだが、このディレクトリへのパスが通っていない。しかし、なぜか/usr/include/c++/v1/cxxabi.hだけは存在するので/usr/include/libcxxabi/__cxxabi_config.hを#includeしようとして見つからないエラーが出る。

仕方がないので、Clangのオプションに-I/usr/include/libcxxabi/を渡してパスを追加した。

もうひとつ、どうもlibc++ 3.7のstd::stringの実装に問題があるようだ。/usr/include/c++/v1/stringの1326-1331行は以下のようになっているが、

    _LIBCPP_INLINE_VISIBILITY explicit basic_string(const allocator_type& __a)
#if _LIBCPP_STD_VER <= 14
        _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value);
#else
        _NOEXCEPT;
#endif

1936-1940行は以下のようになっており


template <class _CharT, class _Traits, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
basic_string<_CharT, _Traits, _Allocator>::basic_string(const allocator_type& __a)
    : __r_(__a)
{

basic_stringのコンストラクターの宣言にあったnoexceptが定義には存在せず、宣言の不一致でエラーになる。

パッケージ管理されているファイルを弄りたくはないので、とりあえず別のディレクトリにコピーしてコードを修正し、そのディレクトリへのパスを追加することで修正した。次のUbuntuのアップグレードの時まで忘れずに覚えていなければならない。

変更自体は、noexceptを付けるだけだ。


~/Documents/src/cpp/include$ diff -u /usr/include/c++/v1/string ./string 
--- /usr/include/c++/v1/string 2015-09-06 19:01:16.000000000 +0900
+++ ./string 2016-04-23 18:59:51.848010811 +0900
@@ -1936,6 +1936,11 @@
 template <class _CharT, class _Traits, class _Allocator>
 inline _LIBCPP_INLINE_VISIBILITY
 basic_string<_CharT, _Traits, _Allocator>::basic_string(const allocator_type& __a)
+#if _LIBCPP_STD_VER <= 14
+        _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
+#else
+        _NOEXCEPT
+#endif
     : __r_(__a)
 {
 #if _LIBCPP_DEBUG_LEVEL >= 2

2016-04-20

江添ボドゲ会@5月

以下の通り5月7日に自宅でボドゲ会を開催するのでお集まりください。

江添ボドゲ会@5月 - connpass

今回もカレーでも作ろうと思う。

curl | bashをサーバーサイドで判定する方法

Detecting the use of "curl | bash" server side | Application Security

ソフトウェアをインストールするとき、シェルスクリプトを実行するのはよくあることだ。しかし、そのシェルスクリプトが他人のリモートサーバーでホストされていた場合、curl | bashするのは危険だ。まともなユーザーは、curl | bashする前に、まず中身を確認して、悪意がないことを確かめるものだ。

しかしもし、サーバー側がwgetやcurlといったツールとブラウザーを判定して、それぞれ別のコードを返した場合どうか。ユーザーが見るのは囮のシェルスクリプトだ。

しかし、それではcurlやwgetを利用してシェルスクリプトをダウンロードするユーザーは騙せない。しかしもし、curlとcurl | bashを判定することができたらどうか。実は、できるのだ。

curlとcurl | bashを判定する方法は、bashの処理にある。bashはコードを順次実行していく。コードの実行中はパイプからの読み出しが滞る。ネットワークとパイプのバッファーが全て埋まってしまえば、サーバーからのデータのダウンロードは中断する。したがって、コードの冒頭にsleepを置いて、バッファーを埋めるために無害で表示されないnull文字を送りつける。ダウンロードが途中で中断すれば、curlはパイプを経由してbashに出力しているのだと判断できる。

curl | bashを判定するサーバーを判定する方法

では、ユーザーはどうやってcurl | bashを判定するサーバーを判定すればいいのだろうか。判定が上に述べたような簡単なディレイで行われているならば、そういうディレイを発生させてやればよい。

curl https://example.com/setup.bash | (sleep 3; cat)

しかし、curl | bashを判定する方法はその他にもあるし、ディレイを複数使って判定することもできるので、確実に判定はできない。信頼できないデータはまずローカルのファイルに落として、中身を検証してから、ローカルのファイルをbashで実行すべきだ。

2016-04-12

Brian Kernighanがプログラミング言語Goの組版に使ったのはなんとtroff

Ramakrishnan Muthukrishnan - Brian Kernighan on the typesetting of "The Go Programming Language" book

L&RのKでありAWKのKでもあるBrian KernighanとAlan Donovanの執筆したThe Go Programming Language(邦訳は丸善からプログラミング言語Goとして6月15日に出版される予定)の組版には、Troff(具体的にはgroff)が使われたそうだ。同本の組版に感心した人間が、Brian Kernighanに組版について以下のようなメールを送った。

親愛なるKernighan教授へ

プログラミング言語Goの本のとても組版が美しい。個人的な感想では、LaTexでクマれたものより美しいように思われる。

同本の執筆手順と本の組版について詳しい説明を願いたい。著作権の項目に使ったツールについては書かれているが。

謝意

Ramakrishnanより

その結果、Kernighanから以下のような返事が返ってきたという。

Ramakrishnanへ

組版について褒めていただきありがたい。組版の大半は単にtroff(実際にはgroff)と-msマクロパッケージで行われた。Latexも少し試したが、私もAlanもその出力をさらに編集する気になれなかったし、Latexを使って組版するのは不可能だと思っている。Troffは私のよく知る昔ながらのツールで、汚く例外的な挙動も多いが、文字を組みたい場所に置いてくれることは確かだ。

入力はXMLで、見出し、パラグラフ、索引、プログラムコード辺、簡単な表などを25個ぐらいのタグで表現している。Goのプログラムでこれを変換した。素早く画面上で見るためと、もし機会があればe-book版のためにHTMLにするのと、印刷のためにtroffにする。XMLを使うのは執筆時にすこし面倒だったが、エラーチェックが便利だった。

細かい修正のために多数のgoプログラムとスクリプトを書いた。例えばすべてのページが同じ高さになるようにtroffの出力を書き換えるとか。生成されたpostscriptにも印刷所の印をいれるために手を入れている。

フォントはAlanの選択だ。適切なフォントを見つけて適切なサイズと見た目にするのにかなり労力を使った。いくつかのアジア圏の文字はうまく扱うのが難しかった。troffは全角Unicode文字を適切に扱えないので、テキストを書きかえてごまかした部分がいくつかある。

図はぜんぶAlanの仕事だった。Googleのドローイングプログラムを使った。pic[画像?、ソフトウェアの名称?]を少し試してみたが、便利ではなかったし、HTMLで扱うためには面倒だった。上付き文字以上の組版が必要な数式は使わなかったし、表は簡素なものだった。eqnとtblぐらいあれば足りるが、HTMLでは扱っていない。

もう少しドキュメントを整備してツールも公開すべきなのだろうが、ほとんどの読者は君のように過程に興味はない。もうひとつの問題として、始めた当初は綺麗で筋の通った設計だったのに、結果として過程は炎上したし、やたら複雑なmakefileを書く必要に迫られた。

メールをありがとう

Brian

ちなみに、GNUのtroff互換実装であるgroffは、ここ10年ほどメンテナーがいなくて保守されていない。

ドワンゴ広告

アスキードワンゴ編集部はlatexを使っているそうだ。ちなみに、日本の殆どの出版社はInDesignで組版をしている。それも、編集者はInDesignを直接触らない。InDesignを触るのは印刷所の人間だ。ある編集者などは、「自分はコンピューターを触らない」と誇らしげに言うそうだ。そういう人は、紙に直接赤鉛筆などで組版の指示をして印刷所に投げる。

私からすると、GUIの組版ツールを使うのは同じ作業を何度も繰り返さなければならず極めて効率が悪いと思うのだが、印刷業界は不思議なものだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-04-06

Vim風のテキストエディターvis

martanne/vis: a vim like text editor

1%のコードで80%のVimの機能を目標に開発されているVim風のテキストエディター。

GUIとマウスのサポートがない以外は興味深い。

2016-04-04

アメリカ合衆国政府が公金を投じて開発されたソフトウェアは自由ソフトウェアにする法案を公開

https://sourcecode.cio.gov/SourceCodePolicy.pdf

Matthias Kirschner's Web log • US government commits to publish publicly financed software under Free Software licenses

アメリカ合衆国政府が、公金を投じて開発したソフトウェアは公共の財産であるのでデフォルトで自由なソフトウェアにする法案を公開している。

これは当然の話で、日本でも速やかに行うべきである。日本国政府が公金を投じて開発させるソフトウェアは自由なソフトウェアとすべきであって、プロプライエタリなソフトウェアの納品は禁止されるべきである。当然、WindowsやMac OS XなどのOSは国家に納品するには適さないOSである。

物理法則が同じかつ1900年ぐらいの科学レベルの異世界にタイムリープした現代人は現代の進んだ科学知識を活用して異世界チート主人公系ラノベのごとくになれるか

いかのような問題提起を考察したい。

なるほど、とても興味深い設定である。これについてできる限り考察してみよう。

異世界チート主人公系ラノベというジャンルがある。一個の現代人の主人公が常識や物理法則の違う異世界に飛ばされて、世界の差異を利用して有意に立つという筋書きの物語である。主人公はどこにでもいる一般人、それも無職とか低賃金有期雇用者とか、社会的弱者であることも多い。

ここでは2016年の人間が1900年に飛ばされて、科学知識の差を利用して活躍する筋書きである。活躍する上で、理解がクソなために科学の発展を阻害するというオチまで付けなければならない。

しかし、実証主義として考えれば、実際に観測可能な現象と一致する結論は、たとえ仮説が間違っていたとしても、科学の発展にはもたらす害悪よりも利益のほうが大きいのではないか。たとえばニュートンは筋金入りの神秘主義者で、現代の常識から考えれば非科学と迷信に凝り固まった人間ではあるが、ニュートンは確実に科学の発展に寄与している。

さて、まず1900年の科学水準について確かめてみよう。ひとまず1900年の日本語版のWikipediaを確認してみる。

1900年 - Wikipedia

  • 1月2日 - 初の電気バスがニューヨーク市で開業
  • 4月11日 - 米海軍が初の潜水艦ホーランド (潜水艦) を取得(就役10月12日)
  • 5月1日 - 東京電気鉄道(後の都電)設立
  • 5月29日 - 米国オーチス・エレベーター社がエスカレーターを商標登録
  • 7月2日 - ツェッペリン(水素ガスによる飛行船)が初飛行(ボーデン湖)
  • 7月19日 - パリ万国博覧会会期中にパリの地下鉄が開通
  • 8月8日 - 国際数学者会議にて、ヒルベルトの23の問題のうちの10題が公開される
  • 9月11日 - 日本初の自動公衆電話が東京の新橋駅と上野駅、熊本市内に設置

後にガンマ線と名付けられる放射線をポール・ヴィラールが観測したのも1900年である。

元素の発見もかなり進んでいて、放射性の元素もかなり発見されていたし、非放射性の元素はほとんど発見されていたし、未発見のものも発見は時間の問題であった。

なるほど、1900年の科学水準というのは、すでに電気バス、潜水艦、電車、エスカレーター、飛行船、地下鉄、公衆電話が存在していたどころか実用化もされていて、かつ数学もだいぶ進んでいたし、放射線の理解も進んでいたし、元素も安定したものはほとんど発見されていた。

さて、困った。1900年は思ったよりも科学水準が高い。例えば筆者程度の人間が1900年に飛ばされても、現代の科学知識を用いてチート主人公になることはできない。

ひとつ考えられるのは、この頃の一般大衆の科学水準はまだ低く、宗教や迷信が強く信じられていて、現代の進んだ心理学を元に大胆に振る舞えば、新興宗教とかネットワークビジネスの開祖としてそれなりに活躍できるのかもしれないし、「まっとうな科学の発展を阻害」するというもうひとつの目的も達成できるのかもしれないが、そういうことができる人間は現代でも新興宗教とかネットワークビジネスの開祖になれるだろう。そして、後述する言語の違いにより、この方法によるチート主人公となるのも難しいのである。

2016年と1900年で大きく違うのは、言語と人権である。この差は、おそらく主人公にはチートどころかハンディキャップになるであろう。

1900年の日本語は、現代と発音が異なる。2016年の主人公が音声学と日本の方言の考古学を専攻していて、かつ発音の実践を積んでいない限り、話し言葉による日常会話は困難であろう。1900年の価値基準で判断すると、主人公は実質的に失語症になってしまう。

書き言葉の差はもっと難しい。主人公が古文漢文に加えて草書体を相当に深く学んでいない限り、1900年の日本社会では文盲の扱いを受ける。当時は、ラテン語の読み書きができないものは論文すら読めずに、科学の世界に足を踏み入れることさえできない。文章で科学知識を伝えられなければ、いかに2016年の第一線の科学知識を持っていいようと無力である。英語はまだ世界共通語の地位を確立しておらず、ドイツ語やフランス語も科学の世界ではまだ強い力を持っていた。

たとえ筆者が2016年の最新の科学技術の知識を持っていて1900年において文書で書き残したとしても、その内容の解読には長い年月がかかり、功績が理解されるのは主人公の死後50年以上かかるであろうし、その頃には主人公の書き残した科学技術は独立して発見されているであろうから、社会への影響は、一部の歴史学者の混乱を除いて、良くも悪くも与えないだろう。

1900年においては、人権はかなり軽視されていた。たとえば1900年の1月23日には、光明寺村女工焼死事件が起こっている。これは織物工場で働く労働者の寄宿所が火事になったのだが、当時の慣習として、労働者の逃亡を防止するために、寄宿所の窓は鉄格子の上、ドアが施錠されていたから、労働者は逃げられなかったのだ。

リンカーンによる奴隷解放宣言は1862年であったが、アメリカ合衆国において黒人が選挙権を実際に行使できるようになるのは1971年からであった。

これを考えると、1900年に飛ばされた主人公は意思疎通ができず知的障害とみなされ、日銭を稼ぐために奴隷のような劣悪な労働環境に身をやつすことになるだろうと予想できる。

考察結果として、1900年の科学水準はかなり高く、2016年の一般人程度があやふやな科学知識を振りかざした程度では、異世界召喚系ラノベのような活躍はできないことが判明した。

2016-04-01

C++標準化委員会の文書: P0200R0-P0209R0

P0200R0: A Proposal to Add Y Combinator to the Standard Library

lambda式で再帰できるようにするY Combinbatorライブラリの提案。

int main()
{
    auto gcd = std:y_combinator( []( auto gcd, int a, int b ) -> int
        {
            return b == 0 ? a : gcd( b, a % b ) ;
        } ) ;

    std::cout << gcd( 20, 30 ) << std::endl ;
}

実装例

template < typename Fun >
class y_combinator_result
{
    Fun f ;
public :
    template < typename T >
    explicit y_combinator_result( T && fun )
        : f( std::forward<T>(fun) )
    { }

    template < typename ... Args >
    decltype(auto)
    operator () ( Args && ... args )
    {
        return f( std::ref(*this), std::forward<Args>(args)... ) ;
    }
} ;

template < typename Fun >
y_combinator_result<std::decay_t<Fun>> y_combinator( Fun && fun )
{
    return y_combinator_result<std::decay_t<Fun>>(std::forward<Fun>(fun)) ;
}

[PDF] O0201R0: A cloning pointer-class for C++

コピー時にポインターの参照先をディープコピーするclone_ptrの提案。

int main()
{
    auto p1 = std::make_clone_ptr<int>(42) ;
    auto p2 = p1 ;
}

これは、以下のようなコードと同じ意味になる。

int * p1 = new int( 42 ) ;
int * p2 = new int( *p1 ) ;
delete p2 ;
delete p1 ;

また、clone_ptrは初期化時に渡されたmost derived typeによるポリモーフィックな型のディープコピーや破棄が正しく行える。


struct Base
{
    virtual void f() = 0 ;
    ~Base() { } // virtualデストラクターではない
} ;
struct Derived
{
    void f() override { }
    Derived() { }
} ;

// 実行時型
clone_ptr<Base> p1( new Derived() ) ;
auto p2 = p1 ;

// ディープコピーが行われる
assert( p1.get() != p2.get() ) ;
// Baseではなく実行時の型であるDerivedとしてコピーが行われる
assert( dynamic_cast< Derived * >(p2.get() != nullptr )

// p1, p2の破棄では、Derivedのデストラクターが呼ばれる

shared_ptrと同じだ。

コピー時にディープコピーを行うクラスのデータメンバーとして生のポインターの代わりに安全に使えるので入るべきだ。

A Proposal to Add Constexpr Modifiers to Functions in <algorithm> and <cstring> Headers

<algorithm>と<cstring>をconstexpr対応にする提案。イテレーターのconstexpr化は別の提案で行う。

<algorithm>をconstexpr化する提案。多くのアルゴリズムは<cstring>に依存しているので、<cstring>もconstexpr化する。

std::memcpyやstd::memmoveは、void *型の引数を取るので、本来constexpr化できないのだが、constexpr化しないとライブラリ実装はcompiler intrinsicsを使うだけなので、constexpr化する。

P0203R0: Considerations for the design of expressive portable SIMD vectors

SIMD型の提供に関する考察。

P0205R0: Allow Seeding Random Number Engines with std::random_device

乱数エンジンをrandom_deviceで初期化できるようにする提案。

現状では、random_deviceからビット列を手動で取り出して乱数エンジンに食わせてやらなければならないが、乱数エンジンの内部状態が何ビットなのか得る方法がないため、適切な初期化が移植性の高い方法で書けない。

これは当然入るべきだし、そもそも最初から入っているべき機能だ。

P0206R0: Discussion about std::thread and RAII

threadのデストラクターが実装された時に、threadがjoinableであると、terminateが呼ばれる。これは様々な問題を引き起こす。しかし一方で、この挙動のほうが好ましい場合もある。

この文書は、threadのデストラクターは自動的にjoinを呼ぶ変更か、自動的にjoinを呼ぶ別のthread型を追加する文面案を提示している。

既存のコードの挙動を変えないために別の型にすべきだろう。

P0207R0: Ruminations on lambda captures

lambada式で値によるデフォルトキャプチャー[=]が使われた場合、クラスのメンバーはthisポインター経由ではなく、値によるキャプチャーになるように挙動を変更するとどうなるかを考察。

この文書は、既存の挙動は変えないことを推奨している。

筆者は変えるべきだと思う。

[PDF] P0208R0: Copy-Swap Helper

強い例外安全を実現するために、まずオブジェクトをコピーして改変し、改変が例外を投げなければswapする。改変が例外を投げた場合元のオブジェクトは変更されないという処理を行うヘルパー関数の追加。

文面案のcopy_swap_helperの宣言が間違っている気がする。

[PDF] P0209R0: make_from_tuple: apply for construction

tupleの各要素をコンストラクターに渡してオブジェクトを構築してくれるmake_from_tupleの提案。

以下のように使う。

struct X
{
    X( int, double, std::string ) ;
} ;

auto t = std::make_tuple( 1, 2.0, std::string("3") ) ;

auto x = std::make_from_tuple<X>( t ) ;
// 以下と同じ
// auto x = X( get<0>(t), get<1>(t), get<2>(t) ) ;

すでにtupleの各要素を関数の引数に渡してくれるapplyがあるが、

void f( int, double, std::string ) ;

std::apply( t, f ) ;

make_from_tupleはそのオブジェクト構築版と言える。

同様にして、placement newしてくれるuninitialized_construct_from_tupleがある。

alignas(X) char buf[sizeof(X)] ;
X * ptr = std::uninitialized_construct_from_tuple<X>( buf, t ) ;

実装は以下のようになる。

template < typename T, typename Tuple, std::size_t ... I >
T make_from_tuple_impl( Tuple && tuple, std::index_sequence<I ... >  )
{
    return T( std::get<I>( std::forward<Tuple>(tuple) )... ) ;
} ;

template < typename T, typename Tuple >
T make_from_tuple( Tuple && tuple )
{
    return make_from_tuple_impl<T>(
        std::forward<Tuple>(tuple),
        std::make_index_sequence<
            std::tuple_size_v< std::decay_t<Tuple> >
            >()
        ) ;
}

ドワンゴ広告

Ubuntu On Windowsでドワンゴ社内の支給PCの勢力図が塗り替えられそうな気がするが、いい加減に支給PCのWindowsぐらい最新にするべきだと思うしGNU/LinuxをOSの候補に加えるべきだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

Linuxにleftpad()というシステムコールを入れる提案

LKML: Richard Weinberger: New syscall: leftpad()

Linuxカーネルに興味深い日付でleftpad()というシステムコールが提案されている。

最近のnode.js業界の事件を振り返るに、leftpadのような基本的なアルゴリズムの依存はソフトウェアを脆弱にすることが判明した。ledpad[原文ママ]を提供するnode.jsパッケージが消失し、多くのソフトウェアが動かなくなった。

この事件に注目すると、node.jsベースのソフトウェアがLinuxの「ユーザースペースは壊さない」原則に将来的に頼ることができるので、このような機能を提供するのはカーネルの役目であるという結論に至った。

glibcとAndoid[原文ママ]のbionicは、早急にこの新しいシステムコールのラッパー関数を提供してくれることを望む。

leftpadをカーネルに入れたのはLinuxの安定したABIという理由だけではなく、パフォーマンス上の理由もある。

ご存知のように、カーネルでは、すべてが高速でかつ優れている。leftpadには大勢の利用者がいるので、可能な限り高速でなければならない。また、この新しいシステムコールはleft-pad.ioのようなサービスをより高速に安定して提供するのにも使うことができる。leftpad()システムコールが十分に利用された場合、npm()という、カーネルモジュールがnode.jsでよく使う新しい機能を登録できる、ioctl()のように機能する汎用的なシステムコールを付け加えるのも手だ。そのような機能としては、is_array()やis_int()が挙げられる。

[leftpad()システムコールをLinuxカーネルに追加するパッチ]

これを受けて、以下のような返信が行われている。

動いた。このシステムコールの重要性は筆舌に尽くしがたい。提案と実装してくれてありがたい。

パッチを提出する時はcheckpatch.plにかけてくれ。

これはよさそうだが、他のarchに対応させた上で、適切なメンテナーをCCに加える必要があるな。

これはよさそうだが、可能な限り高速にするために、無駄な範囲外チェックなどの分岐は全部除去したほうがよいし、ユーザーのメモリーに直接書き込むことで、無駄なcopy_from/copy_toを除去すべきだ。これにより、遅いkmallocも除去できる。

文章には注意を払ってくれ[ledpadとandoidのtypoの指摘]

参考: 本の虫: npmからkikとその他諸々が消されたまとめ