2008年11月30日日曜日

よいソフトをつくる

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
無題 23:15

そんなの誰だってそうだよ。私は自分がプログラミングが得意な方だと思っているけれど、 Maeve の要求定義と設計に十ヶ月費やした。世間で言う、日常的な、広い意味でのプログラミングの能力と、「要求定義し、設計し、実装し、デバッグし、リリースし、メンテナンスする」という能力は明らかに異なっている。たった一人で後者ができる人間は、プログラマと呼ばれる者のうちのほんの一握りであり、それゆえハッカーだとかなんだとかいう尊称を与えられるのだ。

Joelはよいソフトウエアには10年かかるって言ってなかったっけ?作る側は使う側のことをわかるのに10年掛かるといったところだろう。使い手にあわせて10年かけて作り直し続けるといったところだろう。

Bindといういやなサンプルもあるぞ。まあそれでもHappyなほうだろう。ものすごい数のユーザがいて、ネットを支えているのは事実だ。質としては受け入れがたいとおもう人は山盛りいるだろうが。

結局、使い手と作り手が同じで作り手の能力がきわめて高い場合だろう。最近おもったのは、Linusとgitの関係だ。彼の日課がmergeであることに間違いはない。その要求を満たすためにgitを作ったのだ。

「リリースし、メンテナンス」することを考えると依存するものをpackage化する作業が手動で孤立していることはちょっとねぇ。repositoryをrsyncして、それを自動でrpm化したいのよねぇ。
とにかく凹んでいる暇があったら作るなりしっかり休むなり、意味がある(完成に向かう)方向で時間を使おう。とてつもなく長い道のりなのだから。

2008年11月27日木曜日

コンピュータ教育

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
まったくどこの教官だ、この質問の原因になった課題をだしたのは・・・。
http://mixi.jp/view_bbs.pl?id=37418835&comment_count=0&comm_id=602606

タイトルにある通り、テキストファイルをCSVファイルにしたいと思っております。

コンバートする際の詳細は、テキストファイルを読み込み、任意の文字列があった場合のみCSVファイルに書き出す、というものを作りたいです。

(例)

学生新聞ちゃんぽん○政治
学者学生ちゃんぽん

上記のテキストファイルの「学生」と「新聞」だけ抜き出して以下のように書き出したい


学生,新聞,学生

としたいです。

是非、分かる方いらっしゃいましたらご教授お願いいたします。

perlとかrubyとかpythonとかgaucheとかを使わない理由がわからない。VBでもいいだろうし。すぐに使える正規表現のない言語を選択するのはなぜ?マゾですか?たぶん「わかっている」大概の人は、one-linerで済ませるだろう。(多分、発生回数をカウントしたいだけのだろうから・・・。)メモ用紙を用意して正の字を一杯書くのも、人と場合によっては正しいかもしれない。

ともかく「コンピュータ・リタレシ」として考えた場合大いに問題がある。たとえて言うなら、建設工事現場の杭打ち機をステープラーの代わりに、折り紙の紙を切るのに大型チェーンソーをはさみの代わりに使いましょうみたいなノリだ。

概念的にコンピュータが動くとはどういうことかとか、ネットワークで通信できるのはなぜかとかdatabaseとはなにかを理解させる。つぎにコンピュータを使っていると必然的におこるテキスト処理をある程度(簡単な正規表現くらい)できるようにするのが先だとおもう。メールとかはいまどきほっておいても使えるようになるだろうし。たとえるなら、日常生活で紙を切りたいときに、はさみとカッター、手でちぎるの中から適切に道具を選んでつかえるような感覚を先に養ってほしい。

この辺の感覚を持った人が、発注側にまわるようになっていかないと、ソフトウェアとして何を作ればいいのか決める段階のコストが異様に高くなるし、ばかげた話がまかり通る気がする。コンピュータにまつわるコミュニケーションコストを十分に下げておくことは社会的要請だとおもうのですが、いかがでしょう?

そもそもにC/C++を使わせるためにはいろいろな準備が多すぎる。includeの説明をごまかしたり省略したりせずに、背景事情を含めてまともにできる人はどのくらいいるだろうか?ほかにもgccを使うとしてオプションの意味を説明するとか・・・したくないし、したところで「魚をとる方法ではなく魚をあたえる」ことになってしまう。何がいいたいかというと、情報収集能力(ばりばりにプラットフォーム依存)が前提になっているということだ。情報収集能力をあげる教育をしないと、変化についていけなくなってしまう。

Cに手を出す前に、構成管理ツールを使うことの意味や、文字コードの話、環境の話とかをするべきだろうし、それらを自分で解決できないとわけがわからない。

メモリへのポインタでのアクセスとかを理解させることには教育的な意味は無いとはおもわないが、順序や費用対効果というものがあるだろう。再帰の概念とかも必須だしscheme本を読ませるとか、各種アルゴリズム(quick sortなめたらあかんらしい。正しい実装は少ない。)を理解させるとか、でもこれってリタレシとよぶレベルを大幅に逸脱している。また、何かをセキュアに作ろうと思えば、OSの権限管理の知識は必須だし背景事情も知っている必要がある。体感的にわかるためには管理者経験も必要だろう。

1000行以上のコードを書こうとすれば、アルゴリズムを知っていて、言語の構文を知っていてアドホックに試して学ぶことができる以上のことが求められる。具体的には既存のよいコード(OSS, proprietaryを問わない)を読んでそこから学ぶことだ。モノが動くようにバグを入れないように書こうとすれば、どのような習慣が必要かも知らなければならない。

それでいて、いまどきのmacを買って来るといきなりhttpdが入っていたりしていきなりwebappが書けたり、本を買ってきてCD-ROM丸写しでwebapp動かして、構成するfileを単体のscriptとして動かすことを知らなかったりするんですよ。

いまいい年の大学教官が学生のころのコンピューティング環境はtime sharingとかでその当時のもっとも速いマシンよりも速いマシンをいまどきのガキンチョは一人で遊ぶために使うわけだ(PS3とか)。

旋盤とかの加工機械を一通りもっている町工場と適当なLinuxディストリビューションをもっているということは同じだ。理論上は何でも作れる。ただ作り手を選ぶし、何を作るかは注意深く選ぶ必要があるし、注意深く作る必要がある。またどう流通させるかも大事だ。


かなり話が発散したが、とにかく急激に物事が変わっていてかかわる人の意識や考えが追いついていない部分が多数あるというのは間違いない。また、急激な変化が内在している。その変化を引き起こしている要素への理解ぬきには変化に対応することはできない。リタレシとしてはその部分に触れる程度のことはしてほしいなぁ。

2008年11月26日水曜日

まだまだですな。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
reload [command名]
とかできちゃうとテストして書き換えてリロードしてテストかできるので楽かも。REPループは短いに限る。

gitage > stack
gitage > file ./gitage/specedit/testdata/gauche.spec
gitage > stack
0: <open file './gitage/specedit/testdata/gauche.spec', mode 'r' at 0x2aaaafb8beb8>
gitage > tag push piy
gitage > stack
0: <open file './gitage/specedit/testdata/gauche.spec', mode 'r' at 0x2aaaafb8beb8>
1: <git.Tag "piyo">
gitage > spec
gitage > stack
0: <gitage.specedit.base.SpecFile instance at 0x2aaaafb97a28>
gitage > write test.spec
gitage > !ls
: dist dump.spec gitage.egg-info log MANIFEST setup.py test.xml
build dump gitage gitage-quickstart log2 setup.cfg test.spec


こんな感じに書き換わる。まだName:しか書き換えてないが。

# Spec file to build Gauche RPM package
# $Id: Gauche.spec,v 1.51 2008-02-13 15:32:09 shirok Exp $
# In order to build different encoding-specific packages (like
# Gauche-euc-jp, etc) from a single source rpm, the actual package
# is created as a subpackage. The command
#
# rpm -ba Gauche.spec
# builds three packages:
# Gauche-VERS.ARCH.rpm ;; dummy package (no use; discard it)
# Gauche-ENC-VERS.ARCH.rpm ;; binary package with encoding ENC
# Gauche-VERS.src.rpm ;; source package
%define version 0.8.14
%define encoding utf8
%define threads pthreads
Buildroot: %{_tmppath}/rpm
Group: Development/Languages
Name: gitage
License: revised BSD
URL: http://practical-scheme.net/gauche/
Summary: Scheme script interpreter with multibyte character handling
Source: Gauche-%{version}.tgz
Version: %{version}

知っているだけでもタシになることがある

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
知っていたことは、Forthというスタックに何でもかんでもつんで処理をする言語が存在するということ。処理系を触れたことはないし、もちろんコードを書いたことは無い。stackの代わりにfifoを使った変態処理系でのパズルプログラミングはしたことがあるが。

今書いているpackage作業を助けるツールで、コマンドの出力としてpythonのobjectを取り扱いたいが、=(使いたくない)とかdefとかはいらない状況では、結果をstackに積んでしまうというのはいけているアプローチかもしれないというアイディアを思いつかなかっただろう。

scriptの作業でもshでの作業でもテンポラリの問題がついて回る。pipeは、複雑になってくるとわけがわからない。2つの結果を組み合わせるとかやり始めると「?」だ。

pythonのobjectの状態でstackにつめば幸せ。ipythonをおとなしく使うのも手ではある。ただ、pythonのobjectをそのままいじることは作業の粒度に比べて細かすぎる。拡張コマンドはpythonで書いてdirに突っ込めば起動時に読み込んで登録。標準のcmdを使っているから保管もしてくれます。

fileをあける操作をあっちこちで書かなくていいし。seekし忘れるとわけがわかりませんが。
引数をobjectで渡せます。これはうれしい。type少なくていいし。


gitage > stack
gitage > !dir
: dist dump.spec gitage.egg-info log MANIFEST setup.py
build dump gitage gitage-quickstart log2 setup.cfg test.xml
gitage > file MANIFEST
gitage > stack
0: <open file 'MANIFEST', mode 'r' at 0x2aaaafb94030>
gitage >

2008年11月25日火曜日

mirror

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
http://git.tonic-water.com/mirror/にapacheのmirrorを追加しました。またdirの構成を変更して、手垢がついたものはworksの下にいれることにしました。


La MaraDNSのツリーはどこにあるのだろう。source forgeにはtgzはころがっているがツリーは無いようだ。作者に聞くかねぇ。

悪文

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
わかるように書いてくれ。著者こそ説明できていない。

ネットワーク関係の文章は「機能」に対する名前と「製品の分類」に対する名前がごたまぜになっているのが原因で意味不明になっているのではないかと、私はおもう。

前者なら、文章のはじめに定義して使うべきだ。歴史的経緯があるなら後者だろう。


「ルータとL3スイッチの違い」を正しく説明できますか?
第1回 ルータとL3スイッチが誕生した理由
第2回 ルータとL3スイッチの真の役割とは!?
第3回 [仮想実験]もしルータをL3スイッチに置き換えたら
第4回 [仮想実験]もしL3スイッチをルータに置き換えたら

この文章の著者と編集者が、言葉に注意を払って書いてないことは明白である。
次に具体的な例を挙げる。

例1:「責任分岐点」ってなに?境界「線」だとおもうんですが?




例2: この絵の説明文いわく、「図3● L3スイッチは、ルーティング処理を内部の専用チップで処理するため、高速にパケットを転送できる」だそうだ。どう見ても絵から想像されるパケットの経路とそれから想像されるパフォーマンスの低下(ルータまで遠回り)と、説明文(専用チップ)が一致していない。書くなら、「ルータとL2間のトラフィックを減らすために、ルーティング機能を持たせ、L3となった。そのために追加しなければならない処理は重いため、実装にASICを用いることで解決された」となるだろう。




例3 説明文「図2● PCの台数が増加したため、各セグメントをハブで構成し、ルータによって接続するという形態が広まった」という説明で、ここでの「セグメント」はなに?イーサネットのコリジョン・セグメント、それともTCP/IPのセグメントかい?

絵の下までスクロールすると

その一方で、Ethernet(CSMA/CD:搬送波感知多重アクセス/衝突検出方式)の限界や、オフィス内のレイアウト変更に伴うネットワーク配線変更時の柔軟性などに新たな問題が生じた。こうした問題を回避するために生まれた「L2スイッチ」は、さらに「VLAN(Virtual LAN)」という技術を実装することになる。

とあって、コリジョン・セグメントではないかと推定できる。リピータハブ(ここでダムハブと書くと減点)を探すほうが難しいこの時代になにも説明無しで推定させるのはどうかとおもう。

こんな調子では「ルータ」という言葉が何をさす単語として使われているかは想像絶する。


費用対効果

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ハッカーは もはやルートキットを使わない~感染攻撃を行う脅威全体の1%未満
費用対効果の問題でしょう。そんな手の込んだルートキットを作って感染させるコストが高いからでしょう。


結局のところ、犯罪者は「使う必要がない」というごく単純な理由で、ルートキットをあまり使っていないようだ。ハッカーらは、ルートキット技術を用いる代わりに、ウイルス対策ツールがマルウェアを識別するのを困難にする技術を開発してきた。例えば、1つの悪意あるプログラムについて何千種類もの亜種を作成し、攻撃のたびに切り替えて使うといった手法だ。

すでにあるものの亜種をつくる(自動生成)のほうが手の込んだルートキットを動くようにする(当然デバッグしなきゃいけない、ターゲットのハードは多岐にわたる・・・。)よりはるかに楽なはずだ。そして得られるものは対して差が無い。

踏み台がほしいなら狙い撃ちでルートキットを作るだろう。たとえば特定のlinux distributionを狙って配布元のサーバを破ってバックドアで汚染されたパッケージを配布させるとかね。それでもセキュリティの低いWindows PCを狙うほうが楽だろう。管理者の意識が低いし、台数も多いだろうから。

ひとつの推測としては、昔ながらの腕自慢をしたいハッカーはセキュリティ会社に入って、金のほしい(堕落した)ハッカーは犯罪組織にはいって配下のscript kiddyにツールを供給しているのではないだろうか?腕自慢のための研究をしていて、相手が経済犯であるという認識が欠落してるかもしくは不十分なのではないだろうか。

apacheをgit svnする

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
gauche、linux kernelやpythonにつづいてapacheもmirrorしてみようとおもってgit svnしたら、朝目覚めてもまだ終わってない。いま処理中のrevisionがpythonのそれよりも一桁多くて220000とかある。

asamaにつないだterminalでとり始めたのは失敗だった。うらであがっているeditorをkillするか。

asf/httpdのheadのrevistionは720206だから、最低今日一杯、長くて3日掛かるなぁ。

2008年11月23日日曜日

repackaged

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
I repackaged following softwares. Avalilable at collection


  • python-peckchek

  • python-antiparser

  • python-pydot


Use with good care. NO WARRANTY.

調査していたら、fuzzingねたに舞い戻った。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
haskellにはQuickCheckとかあるようだ。pythonでも調査したけど、peckcheckとかantiparseとかだが、どっちもツリーが公開されていないし、メンテもされてない。みんなどうしているのだろう。

検索しているときに、バカはバカにならない - 書評 - ファジング:ブルートフォースによる脆弱性発見手法を見かけた。この本は買った。へんなコメントがついているが、物書きが出版社にけちつけられないのわからないかなぁ?すくなくとも気安くできることじゃない。その辺は、新聞とかTVが広告主に強い態度に出られないのと同じ。ひろゆきもいっていた。「自分でたしかめろ」ってね。べつに2chのみに当てはまることじゃない。世の中、ただのものは無い。

fuzzingするのはよいのだが、膨大な量のテスト結果とテストデータを生成した場合、切り分けが面倒。git bisecみたいなことのdata versionを実装中。問題を起こす入力は1つの文字じゃく複数の文字からなる文字列なんで、そのままbisecは使えない。文字列のbeginとendを見つけてあげればいい。begin/endはどちらも1点なので、大丈夫なはずだ。例外ケースで2回出てくる場合とかあるだろうが、それはそのときだろう。あとは文字列をfileで与えてあげて、seekするようにする。でないとfileがそこそこでかいときに気楽に文字列をcopyされたくないので。んで、切り出したデータを使ってunittestを追記してくれると幸せだね。

fuzzingネタはtonicに入れよう。binarianがらみは外に出す。lineparserはtonicのライブラリに。同じようなもの書きすぎ。その前にgitで管理したときにtagと連携をとりやすくするためにgitageをなんとかしてbootstrapしないとね。

rpmlint

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
rpmのspec fileのparserを書いていて、ふと気になったので、テストケースに使っているspec fileをrpmlintにかけてみた。linux kernelですら文句を言われるようだ。ほかのpackageのspec fileはおして知るべし。

gitage/rpmspec/testdata/kernel.spec:10: W: hardcoded-path-in-buildroot-tag /var/tmp/%{name}-%{PACKAGE_VERSION}-root
gitage/rpmspec/testdata/kernel.spec:11: W: unversioned-explicit-provides kernel-2.6.27.5
gitage/rpmspec/testdata/kernel.spec: E: no-cleaning-of-buildroot %install
gitage/rpmspec/testdata/kernel.spec: E: no-cleaning-of-buildroot %clean


rpmlintの
一部
。うげー。プログラムというより、データだなこりゃ。check関係のfileはひとつのdirにまとめてpackageにすればいいのに。どうせcheckの内容が対象ごとに書いてあって、fileごとに対象が決まっているとかいうつくりでしょ?ならliblint/とかrules/とかpulgin/とlibcheck/かかにしておけばいいのに。名前空間使え~。

rpmlintはスクリプトからの起動時の起点。
SpeckCheck.pyはすさまじいif文のあらし。こんなコード読みたくない。
lintを書こうとすること自体の発想が力技でバッドノウハウに喧嘩売る行為なので、そういう発想のもとにコードを書けば必然なのかもしれない。

おいらだったらif文の代わりにinstance methodかなんかにして、

437 'no-spec-file',
438 '''No spec file was specified in your RPM building. Please specify a valid
439 SPEC file to build a valid RPM package.''',

みたいな部分はmethodのdocumentにするとか、
検出するためのregexpとhandlerとoutputにするtextが一箇所に集中していないのは読み手に優しくないなぁ。もしくは
regexp_xxx/handle_xxx/document_xxxみたいなconventionを採用するとか。
reportのi18nとかもどうするんだか。

2008年11月22日土曜日

出直し。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
rpmbuild時のログ(一部)

Provides: libexpat.so.1()(64bit) libexpat.so.1.5.2.debug()(64bit)
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: /bin/sh libc.so.6()(64bit) libc.so.6(GLIBC_2.2.5)(64bit) libexpat.so.1()(64bit) rtld(GNU_HASH)
Processing files: expat-debuginfo-2.0.1-1
Provides: libexpat.so.1.5.2.debug()(64bit)
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1


yum update失敗時のログ(一部)

--> Processing Dependency: libexpat.so.0()(64bit) for package: elinks
--> Processing Dependency: libexpat.so.0()(64bit) for package: fontconfig
--> Finished Dependency Resolution
Error: Missing Dependency: libexpat.so.0()(64bit) is needed by package git
Error: Missing Dependency: libexpat.so.0()(64bit) is needed by package wxBase
Error: Missing Dependency: libexpat.so.0()(64bit) is needed by package avahi


libexpat.so.1とlibexpat.so.0は、名前が言うところでは「APIが違うので互換性が無い」。3. 共有ライブラリの「3.1.1. 共有ライブラリ名」を参照。


soname は、「lib」というプレフィックス、ライブラリの名前、「.so」という語句で構成され、さらに後ろに、ピリオドと、インターフェース変更時に必ず増加するバージョン番号、が続きます


fedora掲示板のなんかをみると同じといっている人がいるがねぇ。(おいらは違うとおもうが)

まあ、ソースコードを追えばわかりますが、所詮expatのみの例外だろう。2.0.1からとまっているし。メンテはされているようだが。

で・・・どうすっかなぁ。

ひとつには、expat 2.0.1のyum/rpmのpackage名がexpatであること自体が間違い。so.0なlibraryのpackageがso.1のそれで上書きされてしまう。expat2とか言う名前にしないといけない。仮にそうしたところで、cElementTreeをbuildするときにso.1を使うようにしなけれなならない。expatのpackage名問題をcleanに解決したところでcElementTree側の問題はまったく解決しない。
so.1をso.0としてインストールするdirtyな解決はリスクがでかい。

やはりcElementTreeのbuildの過程がどうおかしいのか追跡する必要がある。

しかしなぁ、状態が悪いとくだらないことも気づかないものだ。

ぶつぶつ2

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
現状の

[nori@asama]~/Desktop/work/expat% ls -ltra /usr/lib64/libexpat*
-rwxr-xr-x 1 root root 708 Jan 7 2007 /usr/lib64/libexpat.la
-rw-r--r-- 1 root root 238708 Jan 7 2007 /usr/lib64/libexpat.a
lrwxrwxrwx 1 root root 29 Aug 13 2007 /usr/lib64/libexpat.so -> ../../lib64/libexpat.so.0.5.0
[nori@asama]~/Desktop/work/expat% ls -ltra /lib64/libexpat.*
-rwxr-xr-x 1 root root 143048 Jan 7 2007 /lib64/libexpat.so.0.5.0
lrwxrwxrwx 1 root root 17 Aug 13 2007 /lib64/libexpat.so.0 -> libexpat.so.0.5.0
[nori@asama]~/Desktop/work/expat% ls -ltra /usr/lib/libexpat*
-rwxr-xr-x 1 root root 706 Jan 7 2007 /usr/lib/libexpat.la
-rw-r--r-- 1 root root 196030 Jan 7 2007 /usr/lib/libexpat.a
lrwxrwxrwx 1 root root 27 Aug 13 2007 /usr/lib/libexpat.so -> ../../lib/libexpat.so.0.5.0
[nori@asama]~/Desktop/work/expat% ls -ltra /lib/libexpa*
-rwxr-xr-x 1 root root 133056 Jan 7 2007 /lib/libexpat.so.0.5.0
lrwxrwxrwx 1 root root 17 Aug 13 2007 /lib/libexpat.so.0 -> libexpat.so.0.5.0


生成したrpm

-rw-r--r-- 1 root root 250604 Nov 22 00:58 /usr/lib/libexpat.a
-rwxr-xr-x 1 root root 817 Nov 22 00:58 /usr/lib/libexpat.la
lrwxrwxrwx 1 root root 17 Nov 22 00:58 /usr/lib/libexpat.so -> libexpat.so.1.5.2
lrwxrwxrwx 1 root root 17 Nov 22 00:58 /usr/lib/libexpat.so.1 -> libexpat.so.1.5.2
-rwxr-xr-x 1 root root 141168 Nov 22 00:58 /usr/lib/libexpat.so.1.5.2

x86_64用が生成されていない。

ぶつぶつ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
expatの2.0.xをgitに持ってきたが、releaseスクリプトがcvs前提のようだ。
しかもそのままだとsoをどういうわけだか作ってくれず。yum installする段でlib64.soが存在しないと騒がれる。gitageから見て孫依存だから勘弁してほしい。

どういうわけだかcElementTreeがbuild時にシステムのexpatをつかってしまい、付属のexpatを使用しない。付属のexpatを使うようにするかなぁ。システムのexpatを書き換えるのはそれほどただしい方向ではないし。

2008年11月21日金曜日

expatのversion

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
expatのversionが.pyと.c、packageが期待している環境と現状の環境で違うらしい。どうしたものか。


[nori@asama]~/Desktop/work/elementtree/work% make test
python selftest.py
elementtree test
/home/nori/Desktop/work/elementtree/work/elementtree/ElementTree.py:728: FutureWarning: This search is broken in 1.3 and earlier; if you rely on the current behaviour, change it to './tag'
FutureWarning
**********************************************************************
File "/home/nori/Desktop/work/elementtree/work/tests/ptest.py", line 1050, in tests.ptest.bug_200708_version
Failed example:
parser.version
Expected:
'Expat 2.0.0'
Got:
'Expat 1.95.8'
**********************************************************************
1 items had failures:
1 of 4 in tests.ptest.bug_200708_version
***Test Failed*** 1 failures.
342 tests ok.
cElementTree test
**********************************************************************
File "/home/nori/Desktop/work/elementtree/work/tests/ctest.py", line 257, in tests.ctest.encoding
Failed example:
serialize(elem)
Expected:
'<tag key="&lt;&amp;&quot;&apos;&gt;" />'
Got:
'<tag key="&lt;&amp;&quot;\'&gt;" />'

2008年11月20日木曜日

Open IDで想定される攻撃

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Openid or ノーマルなusername+passwordのdual認証をTurbogears実装したけど、そもそもにOpenIDが、攻撃対効果の観点で攻撃者からの十分な保護を提供してくれるのかを考えたい。

まずは攻撃者が経済目的(つまりスパムコメント、スパムTBなど)の場合。

リスク1:OpenIDのアカウントがのっとられる。ユーザの責任といえなくも無い。まあphishingとかで抜かれたアカウントを利用してloginされるとどうにもならない。
ただ、攻撃側のメリットがどのくらいあるかというと、そこがはっきりしない。スパムを打ってくる攻撃側は、非常に安いコストでそこそこのリターンを得ることができるから攻撃してくるわけです。ほかのユーザからOpenIDのアカウントを搾取するのにかかるコストは結構高いのではないだろうか。被害者のPCにトロイの木馬とかを仕込めるならOpenIDのアカウントではなく、銀行のアカウントを奪うだろう。となると・・・

リスク2:不正取得したアカウントからのスパミングが攻撃の中心だろう。
ただ、アカウントがbanされたらすぐに死んでしまうので、メールの不正送信ほど攻撃にか掛かるコストは安くは無いはずだ。メールの場合はここの部分をOpen replayや自前鯖等で迂回できる。しかもProviderは戦うためのリソースを持っている(後述)。


リスク3:OpenIDのServerを制限する必要がある。信用するサーバをどう限定するか?Spammerが自前Provider鯖をたててそこの認証を持ってくる可能性がある。
http://www.baldanders.info/spiegel/log2/000407.shtml

とはいえ、OpenIDのProviderは大手が多いはずだから、大手のProviderのみを受け付ければいい。得体の知れないProviderは却下。この辺の社会構造はPKIに似ている気がする。verisignがえらいのと同じようにProviderとしてえらい会社がひとつあれば十分。メールがブラックリストでがんばるところを、ホワイトリストで済ませることができる。日本ならmixiとかgreeとか個人に「社会的な意味で」密着しているタイプのProviderが望ましいかな。提供する側と提供される側の利害が一致していて、SSLとちがって金はらわんでも使えるのがうれしい。ユーザとしても必要以上に秘密を知っている相手を増やさなくていい。

また、でかいところはphishing対策やアカウントの不正取得対策をするパワーを持っているので、それにただ乗りできるのが弱小サイトのメリットでしょうか。そのかわりユーザがどのサイトにloginしているかを知られてしまいますが。秘密を守るなら一箇所に集中して丁寧に守るほうがやりやすいです。弱小サイトが片手間でがんばったところでたかが知れている防御しかできませんから。ならばOpenIDにたよって、しないほうがいい。節約した労力でサービスを充実させるほうが生産的です。

経済的な観点から見てよくできて、時間は掛かるでしょうがweb上の認証のデフォルトになるのではないかとおもいます。


攻撃者が、経済犯ではなく、社会犯の場合は話が変わってくる。社会犯は被害者を貶めることが目的なので、プロフィールやエントリの改竄、被害者が不適切なコメントを残したように見せかけることが目的になる。また犯人は、地球の反対側にいるかもしれない経済犯と異なり、被害者の半径2メートル以内に入ったことがある可能性が高い。極端な話、背後から被害者のパスワードをのぞき見たり、被害者の所有するPCを直接操作して認証情報を抜き取る可能性がある。このようなケースでOpenIDを奪われると被害は甚大だ。ネット上での人格権を侵害されたとも言うべき状況になるだろう。

この辺はRP側が運用で対処するしかないかもしれない。この発言は本人ではない可能性がありますとか、被害者から連絡があった際に事後報告するなど。なんせ足跡つきまくりで露骨にわかるので・・・。

被害者が自覚しにくい被害はloginして情報を覗き見るだけの場合だろう。last loginのIPとその逆引き、時刻を表示するくらいしか思いつかない。

merge: elementtreeとcElementTree

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

[remote "save"]
url = git://git.tonic-water.com/public/elementtree-patched/.git
push = refs/heads/cimple

[branch "cimple"]
remote = save
merge = refs/heads/master

これでcimpleをcheckoutした状態でgit pushすると、remoteのcimpleにpushされます。

[nori@asama]~/Desktop/work/elementtree/c% git push
Counting objects: 109, done.
Compressing objects: 100% (107/107), done.
Writing objects: 100% (109/109), 128.01 KiB, done.
Total 109 (delta 63), reused 0 (delta 0)
To git://git.tonic-water.com/public/elementtree-patched/.git
* [new branch] cimple -> cimple

あとはworkにcheckoutしてworkでマージです。

[nori@asama]~/Desktop/work/elementtree/work% git checkout origin/cimple
Note: moving to "origin/cimple" which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
git checkout -b
HEAD is now at 473727f... added MANIFEST for python setup.py bdist_rpm

workからみてremoteのbranchをlocalにcheckoutし、それをベースにbranchをつくる(cimple)。
そしてmerge

[nori@asama]~/Desktop/work/elementtree/work% git merge cimple
Auto-merged CHANGES
CONFLICT (add/add): Merge conflict in CHANGES
Auto-merged MANIFEST
CONFLICT (add/add): Merge conflict in MANIFEST
Auto-merged PKG-INFO
CONFLICT (add/add): Merge conflict in PKG-INFO
Auto-merged README
CONFLICT (add/add): Merge conflict in README
Auto-merged VERSION
CONFLICT (add/add): Merge conflict in VERSION
Auto-merged samples/simple-ns.xml
CONFLICT (add/add): Merge conflict in samples/simple-ns.xml
Auto-merged samples/simple.xml
CONFLICT (add/add): Merge conflict in samples/simple.xml
Auto-merged selftest.py
CONFLICT (add/add): Merge conflict in selftest.py
Auto-merged setup.py
CONFLICT (add/add): Merge conflict in setup.py
Automatic merge failed; fix conflicts and then commit the result.

レレレのおじさん?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

GIT-RERERE(1) Git Manual GIT-RERERE(1)

NAME
git-rerere - Reuse recorded resolution of conflicted merges

SYNOPSIS
git-rerere [clear|diff|status|gc]


ちょっとウケタ。

_elementtreeへ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
.cでcElementTreeを_elementtreeに直すとかも作業のうちに入る。
で、cElementTree.pyを用意すると・・・。

diffした結果では、やっぱりpython2.6のxml.etreeよりcElementTreeのほうがよりversionが大きい。なので基本はcElementTreeにする。よくわからないのがexpat。expat.hにはどちらも1.95.xと書いてあるが、中身が若干違う。どっちにあわせるべかなぁ~~。

ちなみにローカルにインストールされているexpatは1.95.8だ。

pythonのtrunkがgit svnのエラーで取れていないのはイタイ。

2008年11月19日水曜日

elementtree

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

[nori@housyou]/usr/lib64/python2.4/site-packages% ls cElementTree.so
cElementTree.so
[nori@housyou]/usr/lib64/python2.4/site-packages% ls /usr/lib/python2.4/site-packages/elementtree
ElementInclude.py HTMLTreeBuilder.pyo SimpleXMLWriter.pyc
ElementInclude.pyc __init__.py SimpleXMLWriter.pyo
ElementInclude.pyo __init__.pyc TidyHTMLTreeBuilder.py
ElementPath.py __init__.pyo TidyHTMLTreeBuilder.pyc
ElementPath.pyc SgmlopXMLTreeBuilder.py TidyHTMLTreeBuilder.pyo
ElementPath.pyo SgmlopXMLTreeBuilder.pyc TidyTools.py
ElementTree.py SgmlopXMLTreeBuilder.pyo TidyTools.pyc
ElementTree.pyc SimpleXMLTreeBuilder.py TidyTools.pyo
ElementTree.pyo SimpleXMLTreeBuilder.pyc XMLTreeBuilder.py
HTMLTreeBuilder.py SimpleXMLTreeBuilder.pyo XMLTreeBuilder.pyc
HTMLTreeBuilder.pyc SimpleXMLWriter.py XMLTreeBuilder.pyo


結局、これを実現しなきゃいけないのよね~。
repositoryが別々なのを1つにマージしちゃおうかなぁ~~。履歴が消えてしまうのがイタイのですが。いや、branchの名前をうまく操作してあげれば、何とかなるかも。
mergedなrepositoryを掘るためにpurepythonとcimplとかいうbranchの名前にして
空のrepositoryにそれぞれをpush。空のrepository上でmasterにmerge。あとはdoctestなやつをunittest化してnosetestを使うようにするか。

pythonをupgradeしてもelementtreeのversionが1.3以降にならないのはイタイ。

python2.6のxml.etreeはこうなっている。

[nori@housyou]/usr/local/repos/git/public/python-mirror/python-2.6/Lib/xml/etree% ls
cElementTree.py ElementPath.py __init__.py
ElementInclude.py ElementTree.py


そしてcElementTree.pyの中身は

# Wrapper module for _elementtree

from _elementtree import *

である。だからbuildすると同じ場所に_elementtreeができるはず。.cはModules下にある。
.cな中身はこれで全部なのかはちょっと不明。手持ちのcelementtreeのファイルと中身を比較すればはっきりしますね。まあ明日以降ですな。

[nori@housyou]/usr/local/repos/git/public/python-mirror/python-2.6/Modules% ls _elementtree.c
_elementtree.c

celementtree

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
elementtreeだけでは話にならないというわけでpackagingを試みるわけですが・・・。

bdist_rpmするとここでこけるので

expat/xmlparse.c:23:19: error: ascii.h: No such file or directory
expat/xmlparse.c:85:22: error: internal.h: No such file or directory

とりあえず

gcc -pthread -fno-strict-aliasing -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -fPIC -DXML_STATIC -DHAVE_MEMMOVE=1 -DXML_NS=1 -DXML_DTD=1 -DBYTEORDER=1234 -DXML_CONTEXT_BYTES=1024 -Iexpat -I/usr/include/python2.4 -c expat/xmlparse.c

とやってみる。これはちゃんとコンパイルできる。なぜだ~。

追記:何のことは無い、tgzに入ってないようだ。

drwxr-xr-x nori/nori 0 2008-11-19 22:34:07 cElementTree-1.0.6.fix0/
-rw-r--r-- nori/nori 6158 2008-11-19 22:31:39 cElementTree-1.0.6.fix0/README
drwxr-xr-x nori/nori 0 2008-11-19 22:34:07 cElementTree-1.0.6.fix0/cElementTree.egg-info/
-rw-r--r-- nori/nori 223 2008-11-19 22:34:07 cElementTree-1.0.6.fix0/cElementTree.egg-info/SOURCES.txt
-rw-r--r-- nori/nori 565 2008-11-19 22:34:07 cElementTree-1.0.6.fix0/cElementTree.egg-info/PKG-INFO
-rw-r--r-- nori/nori 1 2008-11-19 22:34:07 cElementTree-1.0.6.fix0/cElementTree.egg-info/dependency_links.txt
-rw-r--r-- nori/nori 13 2008-11-19 22:34:07 cElementTree-1.0.6.fix0/cElementTree.egg-info/top_level.txt
-rw-r--r-- nori/nori 565 2008-11-19 22:34:07 cElementTree-1.0.6.fix0/PKG-INFO
-rw-r--r-- nori/nori 2693 2008-11-19 22:34:06 cElementTree-1.0.6.fix0/setup.py
-rw-r--r-- nori/nori 59 2008-11-19 22:34:07 cElementTree-1.0.6.fix0/setup.cfg
drwxr-xr-x nori/nori 0 2008-11-19 22:34:07 cElementTree-1.0.6.fix0/expat/
-rw-r--r-- nori/nori 32476 2008-11-19 22:31:39 cElementTree-1.0.6.fix0/expat/xmlrole.c
-rw-r--r-- nori/nori 41408 2008-11-19 22:31:39 cElementTree-1.0.6.fix0/expat/xmltok.c
-rw-r--r-- nori/nori 193934 2008-11-19 22:31:39 cElementTree-1.0.6.fix0/expat/xmlparse.c
-rw-r--r-- nori/nori 74357 2008-11-19 22:31:39 cElementTree-1.0.6.fix0/cElementTree.c


追記2:
不良生成なMANIFESTが原因でした。
ちゃんとbuildできるtgzつくるか、まったく何もしないかのどっちかにしてほしい。
Extesionに関してはsetuptoolsは無力だし。:P

やはり・・・。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
心配していたことが起きた。


[nori@asama]~/Desktop/work/gitage/libgitage% yum search mach
There was a problem importing one of the Python modules
required to run yum. The error leading to this problem was:

No module named cElementTree

Please install a package which provides this module, or
verify that the module is installed correctly.

It's possible that the above module doesn't match the
current version of Python, which is:
2.4.3 (#1, May 24 2008, 13:57:05)
[GCC 4.1.2 20070626 (Red Hat 4.1.2-14)]

If you cannot solve this problem yourself, please go to
the yum faq at:
http://wiki.linux.duke.edu/YumFaq


追記:
sudo rpm -U --force python-elementtree-1.2.6-5.x86_64.rpm
で上書きして出直し。
さてcのソースを探さねば。

ほしいものはdatabaseじゃない

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
履歴を管理できるdatabaseかなぁ。
web applicationを一度動かし始めた後は、過去のデータとプログラム側の型の整合性が問題になる。神聖にして不可侵(?)なtableの変更が自由にできればいいのだが。

プログラムはテストを書きながら変更していけば何とかなるが、ユーザが作り出したデータはなかなか微妙だ。過去のデータが「同じ結果を生み出す」ことを保障しようとするとわけがわからない。wikiとかならレンダリング結果が同じ、つまりdom等価ならいいやというのならまだ望みがありそうだが。

「データが書き換わるタイミング」と「プログラムが書き換わるタイミング」の問題。まあ最悪とめればいい。電話システムとかじゃないんだから。

すぐに思いつくのは、

実データに対して安全、気楽(?)にテストを流せる仕組み。
時間軸上での実データセットを指定できる。(version管理)
データをbisecして問題点を自動切り出しする仕組み。

とかかなぁ。

考えてみれば、web applicationてのは設備+データ+プログラムで、構成管理されているのは、現状プログラムだけだ。データや設備も構成管理に含めれることができればより幸せ度は高いはずだ。サービスを丸ごと仮想化して構成管理したいんだよね。

設備は仮想化で何とかできるはず。ネットワークとかは無理かもしれんが。
データもなんとかなるはず。HDDは安いし、あのはてなですら十数GByteだ。

とはいってもsqliteで構成して、dbのファイルをgitに入れるのは明らかにだめだろう。
データベースはasidのためにがんばっているのだから、やっていることはgitなどのrepositoryと根本では近いはずだ。近い将来、出てくるはず。

やりたかったことはこっちだ。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
別にpropertyでなくてよい。classが生成されたときに、継承ツリーに沿って計算してくれればいい。いちいち継承されたクラスでごたごた書いたり、meta classを使う側のクラスの定義を汚し(継承ツリーをたどるコードを書く)たくない。

あとは_xをdelすれば完全犯罪(?)です。


class KlassMeta(type):
def __init__(cls, name, bases, dictionary):
base = cls.__base__
if base == object:
cls.x = dictionary.get('_x', 0)
else:
cls.x = dictionary.get('_x', 0) + base.x

class Klass(object):
__metaclass__ = KlassMeta
_x = 1

class DerivedKlass(Klass):
_x = 2

print Klass.x
print DerivedKlass.x

kp = Klass()
dkp = DerivedKlass()
print kp.x
print dkp.x

実行結果

1
3
1
3

あたまがmetametaでござる。

metaclassでpropertyを使う。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
気持ち悪い。

usual = UsualWayOfUse()
usual.x = 1
print usual.x

print '=' * 60

class KlassPropertyMeta(type):
def fgetx(self):
base = self.__base__
if base != object:
return base.fgetx() + self._x
return self._x
x = property(fgetx, None, None)

class KlassProperty(object):
__metaclass__ = KlassPropertyMeta
_x = 1

class DerivedKlassProperty(KlassProperty):
_x = 2

print KlassProperty.x
print DerivedKlassProperty.x

kp = KlassProperty()
dkp = DerivedKlassProperty()
print kp
print dkp


実行結果

[nori@asama]~/Desktop/study/python/experiment% python classproperty.py
1
============================================================
1
3
<__main__.KlassProperty object at 0x2aaaaab48e50>
<__main__.DerivedKlassProperty object at 0x2aaaaab48e90>

stash

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
事故ってstashをほかのbranchにapplyしてしまって、さらにあるべきブランチをcheckout -fした。なんかだめげ。

あああ、checkout -fしてcheckoutして戻ってきてからapplyしなおせばOKだった。一件落着。

2008年11月18日火曜日

快眠の元

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

[nori@asama]~/Desktop/work/gitage% nosetests libgitage/rpmspec_test.py
...................
----------------------------------------------------------------------
Ran 19 tests in 0.147s

OK

ふう。

unofficial fix start line for elementtree

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
python-elementtree 1.3.a3.fix0 is the base code for unofficial fix.

I gurantee nothing. Use it with good care.

The RPM package will be found in
http://yum.tonic-water.com/collection/

Wanna see code? Here is git repository.
http://git.tonic-water.com/elementtree-patched/

This is based on http://svn.effbot.org/public/elementtree-1.3/

And it is git cloned to http://git.tonic-water.com/elementtree-1.3-mirror/

elementtree v1.3をpackageする。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
まずは準備。

昨日pythonのコードもかっぱらってきたが、1.2の中でも古い部類に入るようだ。ということで、1.3を自分でbugfixしたりpackageしたりする準備。ミラーはdaily syncする必要ないでしょう。開発止まってるみたいだし。


で、python setup.py bdist_rpmするも・・・あれ?

hard linking elementtree/TidyTools.py -> elementtree-1.3a3-20070912-preview/elementtree
hard linking elementtree/__init__.py -> elementtree-1.3a3-20070912-preview/elementtree
creating dist
tar -cf dist/elementtree-1.3a3-20070912-preview.tar elementtree-1.3a3-20070912-preview
gzip -f9 dist/elementtree-1.3a3-20070912-preview.tar
removing 'elementtree-1.3a3-20070912-preview' (and everything under it)
copying dist/elementtree-1.3a3-20070912-preview.tar.gz -> build/bdist.linux-x86_64/rpm/SOURCES
building RPMs
rpmbuild -ba --define _topdir /home/nori/Desktop/work/elementtree/work/build/bdist.linux-x86_64/rpm --clean build/bdist.linux-x86_64/rpm/SPECS/elementtree.spec
error: File /home/nori/Desktop/work/elementtree/work/build/bdist.linux-x86_64/rpm/SOURCES/elementtree-1.3a3_20070912_preview.tar.gz: No such file or directory
error: command 'rpmbuild' failed with exit status 1

なんでだ?

[nori@asama]~/Desktop/work/elementtree/work% ls build/bdist.linux-x86_64/rpm/SOURCES
elementtree-1.3a3-20070912-preview.tar.gz

は?!-と_が違う!

よくわからないが

#from distutils.core import setup
from setuptools import setup
...snip...
#version=open("VERSION").read().strip(),
version='1.3a3-20070912-preview',

とかしてsetup.cfgを追加してごまかす。gitなときはversionをみんなどうしているんだろう・・・。


追記:
原因はこの子ですね、おそらく。
/usr/lib64/python2.4/distutils/command/bdist_rpm.py
でこんなことになってます。しかしわかったところねぇ・・・。

def _make_spec_file(self):
"""Generate the text of an RPM spec file and return it as a
list of strings (one per line).
"""
# definitions and headers
spec_file = [
'%define name ' + self.distribution.get_name(),
'%define version ' + self.distribution.get_version().replace('-','_'),
'%define release ' + self.release.replace('-','_'),
'',
'Summary: ' + self.distribution.get_description(),
]

2008年11月17日月曜日

しまつた。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
elementtreeの1.3からのfeatureを使ってしまった。

→Last updateが2007とかだめじゃん。

2.5からpythonの標準ライブラリに取り込まれたんだっけ?

pythonをgit-svnしてしまえ。(これが間違い!!)

revisionが67240とかなのに、始めて10分でまだ5000とかだ・・・。

そうだよ、matzがrubyをgitするのに一晩掛かったのだから、同じことだ。

elementtreeのversionだけでここまではまるとは。うかつだった。
python本体のversionをあげたり、混在したりするつもりはあまり無いです。yumとかが依存しているので混乱の元です。/usr/local/binにいれるのは手ですが、やっぱりやだなぁ。だってpythonまわりがdriesとかから入れているrpmだから事故りたくない。


見ていると1revision/1秒なんで60000秒つまり1000分それは18時間とかか?今日はもう寝ようか。。。。まあ、一度とってしまえば、ローカルにヒストリを含めて持っているのは幸せだろう。git-svnでネットワーク越しにimportするよりsvnでmirrorしてからローカルでimportしたほうがよかったかもしれないが、もう間に合わないだろう。repositopry全体をtgzしたものとかは落ちていないだろうし。

ちなみにCPU負荷は6%x2くらい(2.5と2.6を同時にimportしている)ためです。おそらくDisk I/O boundでしょう。gyaoは普通に視聴できてたし。

追記:
diskでもないなぁ・・・。なんだろう。メモリ帯域?、プライオリティが間違っている?・・・niceは15だしなぁ。

sudo /usr/sbin/lsof -i -P | grep git
でなんとなくわかった。tcp connect/closeを繰り返すらしい。そりゃだめだわ。

git-svn 13378 gitbot 4u IPv4 23937457 TCP housyou:58265->svn.python.org:80 (CLOSE_WAIT)
git-svn 13378 gitbot 7u IPv4 25139921 TCP housyou:60507->svn.python.org:80 (ESTABLISHED)
git-svn 28084 gitbot 4u IPv4 24045356 TCP housyou:36746->svn.python.org:80 (CLOSE_WAIT)
git-svn 28084 gitbot 7u IPv4 25138436 TCP housyou:60506->svn.python.org:80 (ESTABLISHED)
git 29497 gitbot 4u IPv4 24045356 TCP housyou:36746->svn.python.org:80 (CLOSE_WAIT)
git 29497 gitbot 7u IPv4 25138436 TCP housyou:60506->svn.python.org:80 (ESTABLISHED)
git 29507 gitbot 4u IPv4 23937457 TCP housyou:58265->svn.python.org:80 (CLOSE_WAIT)
git 29507 gitbot 7u IPv4 25139921 TCP housyou:60507->svn.python.org:80 (ESTABLISHED)

Intel Core i7

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
売り出されたみたいですね。

安定したMB、対応したLinuxが手に入るまで関係ないですが、ロードマップを知っておくことはよいことなので、ちょっくら調査。


使われていないCPUコアを動的に停止させ,TDP(Thermal Design Power:熱設計電力)の許す限り,残りのコアの動作クロックを引き上げることができる「Turbo Mode」がサポートされている。


Coreごとにクロックを変更できるらしい。また、稼動していないコアは電力を止められる。OS のプロセス管理やOS仮想化との兼ね合いがどうなるのか興味深いところです。

OSの歴史はプロセスの切り替えができる、複数ユーザのサポート、プロセスの切り替えが強制(プリエンプティブ、真のマルチタスク)、複数プロセッサ、仮想化と進んできている。複数プロセッサや仮想化の次になにが来るのかは想像がつかない。ただ間違いが無いのは複数のプロセッサに「賢く」タスクを割り付けることができることがOSの価値の一部を作ることは間違いないだろう。

いまだにシングルプロセッサでもタコなことはいくらでもあるが(UIがとまるとか)。まあ、OS側でタスクの意味(backgroundでちまちまこなしていけばいいのか、UIのイベントなのできたらすぐにこなしてほしいが重くは無い)を理解していないのでしょうがないとも言うが。APIを通してプログラマに決めさせるのはナンセンスなので、プログラムの挙動から推定するか走っているときにユーザにプロセスのタイプを指定させるしかないのだろう。

そのうちにシステムが、測定ベースでTDPを自動認識するようになるのも時間の問題だろう。だって温度計もついているし、消費電力も測定することが可能だろうから。

2008年11月13日木曜日

パッケージ管理

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
rpm+yumでおおよそ満足(70点)くらいなのだが、いろいろと。

rpm+yum

  • distribution標準

  • 依存性解析が遅いときがある

  • 大量(100>)にupdateするとおかしくなることがある。とくにyum自身が書き換わる場合。さきにyum update yumすべし。

  • プラットフォーム依存

  • binary生成が簡単とはいえ手動、rpmbuild -taなど

  • 何も考えなくていいので楽

  • build済みなので速い、とくに台数が多いときは有利だろう

  • yumのサーバ(createrepo + http)を立てて、そこを参照すればかなり自由にできる



setuptools/easy install(python)

  • pythonの世界、でもまあ、setup.py bdist_rpmで回避可能なことも。

  • プラットフォーム依存していない

  • 依存性管理がタコな時がある。rpmでいれたpackageがversion管理用のfile(egg-info
    )を持っていないときなど

  • package serverの立て方は?(知らないだけだとおもうが・・・)



macportsの不満点

  • 標準じゃない(finkも同じ)

  • 作り方不明

  • 依存解析が遅い

  • buildに失敗することがある。

  • buildするので時間が掛かる。作業台数が多いときはひどい目に遭いそう。


う~んこれだけ書いただけでもこなれてない感じがする。
redhatに乗っかっているcentosと比較するのが間違いだが。


しかしなんでどいつもこいつも依存解析が遅いのだろう?naiveにはsatisfiedとrequestedの辞書を持っていて、

最初は両者とも空
requestedにインストール要求されたpackageが入る

while requested:
requestedからpackageを取り出す。
packageが依存するpackageでa)かつb)なものをrequestedに追加する。
  a)satisfiedに存在しない
b)systemに存在しない
取り出したものをsatisfiedに入れる。
assert requestedは空
satisfiedに残ったものをインストールする。

とかになるとおもう。なんでこれが遅いんだか。

本当はrpmbuildに必要なデータを取ってくる方法を記述したfileを用意してそれに対してrpmbuildが走り、rpmがcacheされるような仕組みがいいんですけどね。portsとrpmのいいとこ取りみたいな。
fileにsourceをgetする方法を記述しておけば(たとえばsvn updateなりgit pullなり)、
勝手にversion番号を打ってくれて、rpbuild。あとはyumでウマーな仕組み。

gitのある生活(2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
今日は、myserverにgit pushするための設定です。
client, serverはともにLANにあるものとします。つまり認証なしのケースです。

この例での作業フローはoriginでclone/fetchをcrontabで行っています。それをbranch masterにpullしてきてローカルでマージし、こんどそれをlocalのbackgammonbaseにmergeします。最後にmergeしたbackgammonbaseをworkにpushします。

client側の設定です。まあ、branchごとに対応するremoteを設定できることがよいところでしょう。masterをcheckoutしてgit pullと打てば、git.tonic-water.comからとってきますし、backgammonbaseをcheckoutしてgit pushと打てばwork.tonic-water.comにpushされます。

[remote "origin"]
url = http://git.tonic-water.com/gnubg-mirror/.git
fetch = +refs/heads/*:refs/remotes/origin/*

[remote "save"]
url = git://work.tonic-water.com/gnubg/.git
fetch = +refs/heads/*:refs/remotes/origin/*

[branch "master"]
remote = origin
merge = refs/heads/master

[branch "backgammonbase"]
remote = save
merge = refs/heads/master


サーバ側の設定
git daemonのためにport9418をあけましょう。
使用したいrepositoryをおくdirを決めましょう。今回は
/usr/local/repos/git/work
におくことにしました。この下に/gnubg, /gnubg/.gitが配置されています。

server.shを用意しましょう。中身はこんな感じです。

#!/bin/sh
git-daemon --verbose --base-path=/usr/local/repos/git/work --reuseaddr --export-all --syslog --detach

manに書いてありますが、reuseaddrはつけておいたほうが無難でしょう。再起動をかけたときにすぐつながるし。--syslog --detachは動くようになってからつけましょう。base-pathはapacheでいうところのDocumentRootですな。--export-allしない場合はdirごとになんかfileをおいてコントロールするらしい(エラーしやすい気がするからあまりよいソリューションとは思えないが・・・)。私は、特定のdirの下を再帰的に特定用途に使うほうが筋がよいとおもっているのでexport-allです。

server.shを適切な権限で実行します。privilege dropしているとは思えないので、普段使うユーザアカウントやrootで実行しないようにしましょう。念のため。

gnubg/.gi/configtはこんな感じです。書き加えられているのはdaemonの部分で、どういうことかはmanを参考にしてください。この設定は認証が無いのでセキュアなLANからのみ使用可能にしましょう。私のLANは有線しかないです。

[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[daemon]
uploadpack = true
uploadarch = true
receivepack = true
[remote "origin"]
url = http://git.tonic-water.com/gnubg-mirror/.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master

2008年11月12日水曜日

asm習作

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
感想

  • 寝癖およびAT&T formatとintel formatの違いで頭がぐしゃぐしゃ。

  • divで割られるreigsterがedx:eax固定。恐怖のRISC脳はsrc/dst合計4つを想像する

  • test x xとかxor x xとか。恐怖のry




unsigned int
asm_gcd(unsigned int x, unsigned int y)
{
/* asm memo
* mnemonic: div
* to be diveded edx:eax
* diveded by source: r/m32
* result
* div -> eax
* mod -> edx
*/
/*
skelton
div, mod = divmod(x, y)
divmod(y, mod)
*/
/*
implementaion idea (intel format)
eax, edx = div(edx:eax, ecx)
mov eax, ecx; # next x(1)
mov ecx, edx; # next y
mov edx, 0; # next x(2)
loop if ecx:
return eax
*/
assert(x >= y);
__asm__ __volatile__(
"init: \n\t"
" xor %%edx,%%edx \n\t"
"while: \n\t"
" div %%ecx \n\t"
" mov %%ecx,%%eax \n\t"
" mov %%edx,%%ecx \n\t"
" xor %%edx,%%edx \n\t"
" cmp %%edx,%%ecx \n\t"
" jne while \n\t"
: "=a"(x):"a"(x),"c"(y));
return x;
}

unsigned int
w_gcd(unsigned int x, unsigned int y)
{
unsigned int z;
while(y){
z = y;
y = x%y;
x = z;
}
return x;
}

unsigned int
c_gcd(unsigned int x, unsigned int y)
{
if(y){
return c_gcd(y, x%y);
}
return x;
}

int
main(int argc, char**argv)
{
assert(c_gcd(1, 1) == 1);
assert(c_gcd(4, 2) == 2);
assert(c_gcd(4, 3) == 1);
assert(c_gcd(12, 3) == 3);
assert(w_gcd(1, 1) == 1);
assert(w_gcd(4, 2) == 2);
assert(w_gcd(4, 3) == 1);
assert(w_gcd(12, 3) == 3);
assert(asm_gcd(1, 1) == 1);
assert(asm_gcd(4, 2) == 2);
assert(asm_gcd(4, 3) == 1);
assert(asm_gcd(12, 3) == 3);
assert(asm_gcd(15, 3) == 3);
assert(asm_gcd(144, 64) == 16);
return 0;
}


ちなみに-O2でコンパイルするとw_gcdもc_gcdは同一のasmに落ちて、手で組んだコードとほぼ同じになる。末尾最適化とレジスタ割付の最適化はちゃんと行われているようだ

.globl w_gcd
.type w_gcd, @function
w_gcd:
.LFB28:
test %esi, %esi
mov %eax, %edi
jne .L7
jmp .L2
.p2align 4,,7
.L9:
mov %esi, %edx
.L7:
xor %edx, %edx
div %esi
mov %eax, %esi
test %edx, %edx
jne .L9
mov %eax, %esi
.L2:
rep ret



.globl c_gcd
.type c_gcd, @function
c_gcd:
.LFB29:
test %esi, %esi
mov %eax, %edi
jne .L17
jmp .L12
.p2align 4,,7
.L18:
mov %esi, %edx
.L17:
xor %edx, %edx
div %esi
mov %eax, %esi
test %edx, %edx
jne .L18
mov %eax, %esi
.L12:
rep ret

2008年11月8日土曜日

塞翁が馬

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
loadとaddの依存関係を解析してpipelineがとまらないようにする話は、耳にタコができるほど聞いたが、addでoperandにaddressをとれるというのは、依存関係の解析の手間が省けるから中の人は楽なのかもしれない。load addって命令が連続しているのを調べて、loadをaddより十分先行させないとaddがメモリ読み出し待ちになってしまうからな。load addが依存しているのをloadさきのregisterとadd元のregisterが同じということからみつけるのと、そもそも1つの演算である場合では後者のほうがはるかに楽だし。

とにかく直交性の高い素片に分解してしまえという考え方は、最終的な演算の直前なら正しいのかもしれないが、プログラムがコンパイルされた時点にすることとして正しいかどうかは疑わしい。実行codeから依存関係を知るコストが高いので。

さらに命令セットの寿命とプロセッサ設計の寿命は前者が圧倒的に長い一方で、直交性をあげることでのゲインの具合とその箇所はプロセッサ設計の寿命に依存していて、商業的には損な選択なのかもしれない。

μOPはよく考えられているのか運がいいのか。命令セットを変えられないのは64bit化のときにIntelがポカをやったことからあまりにもclearだ。しかしまあ、LLしてておもうのは
source code -> byte code -> VM -> x86 instruction -> CPU -> μOP
というたくさんのステップを経て実行されているんだよね~。byte codeと機械語の差って大きいねぇ。VM上でμOPにJITできたら幸せかもしれないが、仕様が公開されることは無いだろうしなぁ。

とまあ、まったくまとまりなくだらだらしてみました。

goto in python

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
http://entrian.com/goto/
jokeらしいが。assemblyから直接pyにmapするような場合にはgotoがないと苦しい。

exceptや関数を飛び越えられないという制限はべつに問題ないしねぇ。


from goto import goto, label

print 'hello'
goto.skip
print "won't be seen"
label.skip
print 'bye'

2008年11月7日金曜日

gcc memo

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

-m32

32bit、ええx86_64なマシンだと-m64に相当するので。諸般の事情でpointerは32bitであってほしいときなのです

-march

アーキテクチャの指定。64bitなマシンだと、-m32を使わないとi386とかは指定不能。

-masm=intel

-Sの時に吐く.sのformatをintelにする。


何をしているかって?32bitのintel formatなアセンブリを生成したかったのですよ。

LinuxとSSE

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
これを読んでいてふとおもったのだが、


アイコン 「AVXをどう使えばいいの?」「使うべきじゃない」

 Intelは、2010年にコードネーム「Sandy Bridge」において、x86プラットフォームに「YMMレジスタ」と呼ばれる256bitのレジスタを新設し、それに対するSIMD命令群を追加することを発表しました。これを「Intel AVX(Advanced Vector Extensions)」と呼んでいます。

 Agner Fogは、AVXにおいて「XSAVE」「XRESTOR」という新しいレジスタ退避命令が追加されるようであるが、ドライバ開発者はどうやってこのレジスタを使えばいいの? と尋ねました。それに対してArjan van de Venは、「使うべきじゃないよ。SSE(注)を使うべきじゃないのと同じ理由でね」と答えました。
注:SSE(Streaming SIMD Extensions)とは、Pentium IIIから搭載されているSIMD拡張命令セットのこと。SSE(無印)からSSE4まであるが、ArjanはXMMレジスタ(SSEレジスタ)を使う命令全般を「SSE」とひとくくりにしています。

 Andi Kleenはさらに、「まず、ドライバがカーネルインターフェイスを使わずに勝手にXSAVE、XRESTORを使った場合はカーネルが死んでしまう。決してやってはいけない。カーネルインターフェイスを使うべきだ。カーネル本体のコードは2.6.27で入るよ。でもFPUやSSEなどと同じで、使用されるときだけLazyにレジスタ退避を行う仕様になるので、ほとんどのドライバでは使うと性能が劣化するだろう」と補足しています。

 2010年に登場予定の機能が、パフォーマンス得失まで含めてすでに議論がされていることにちょっと驚いてしまいますね

はあ。。。

いままで適当にgnubgをbuildしていたけど、SSE関係をチェックしてちゃんとbuildされているか検証しよう。また仕事が増えた。あとそれからasmを生でいじるのもありだな。かなりしっかりしたテストsetを用意する必要があるが。

2008年11月5日水曜日

x86でのセマフォ実装?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

label: 00406BEA
mov ecx, FFFFFFFF
xchg dword[esi+14], ecx
test ecx, ecx
jne 00406BEA

最初意味がわからなかったが、おそらくatomic exchange and testってやつだ。
大学の研究室時代を思い出した。当時はinner loopにしか興味が無くて(行列とかのHPCなのだ)、RISCの命令の中ではずいぶんと遠く(基盤の上バス)まで影響の出る命令があるもんだと印象に残った。

ほかのRISCの命令・・・とはいってもmull/add/loadとかばっかしで単純で、bspがどーのこーのとかはあまり気にすることはなかった。そいつらが綺麗にならんでくれることが大事で、そいつらがstallしないことがすべてだった。xchgでとまるなんてあまり興味が無かった。

時は流れてHT全盛で、遅いメモリアクセスを使ってlockするのが仕方ないのが結構影響ありそうなアプリは世の中山盛りのようだ。

で、Intelのドキュメント(IA32)によると、

XCHG (exchange) 命令は、2 つのオペランドの内容を入れ替える。この命令は、3 つのMOV命令と同じ効果を持つが、一方のオペランドをロードする間に他方のオペランドの内容を保存するための一時的なロケーションを必要としない。XCHG命令でメモリ・オペランドを処理するときは、プロセッサのLOCK 信号が自動的にアサートされる。この命令は、プロセスの同期をとるためにセマフォまたは同様のデータ構造を実装するのに便利である(バス・ロックについての詳細は、『IA-32 インテル®アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル、下巻』の第7 章の「バス・ロック」を参照)。


ここまでよんで、あああ~~atomic exchangeなのね。了解。マルチスレッドとかじゃないなら、とりあえずは無視だな。

「x86 セマフォ xchg」でgoogle神に神託したらObj-C 最適化:不可分な操作とか転がり出てきた。

日本語でわかりやすそうな記事は4.Atomicなメモリ書き換えとかだな。

MySQLのバグレポートに完全におなじassmelbyが出てくる。

Use GCC-provided atomic lock operations to replace pthread_mutex_lock functions


At least it doesn't hurt. Since we use xchg for both lock and unlock.
Here is the assembly code:

lock:
00000000000005b0 :
5b0: b8 01 00 00 00 mov $0x1,%eax
5b5: 86 47 08 xchg %al,0x8(%rdi)
5b8: 84 c0 test %al,%al
5ba: 75 04 jne 5c0

assemblyのoperandの順番が違うのに注意ね。

関数呼び出し

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
callは関数呼び出しなんだろうが、その前にいろいろpushしている。leaはebxになんか値をロードしている。
このへんとか見る限り、callの前にpushしたものは引数と見ていいだろうが、どこのpushがそうなのやら。
呼び出し側と呼び出され側を突き合わせて推測するのだろうが。

ともあれ呼出規約@Wikipediaを参考に、近そうなやつはどれかあたりをつけよう。
callしたあと、ガシガシjumpしたり次の処理をやっていて、「add esp, 12 ;スタック上の引数を除去」の形跡がないから、Pascal系の規約を想定したほうが賢いだろう。まあ、0個の引数の可能性やfastcallも否定できないが。

x86(IA-32) アーカイブ
とかかなぁ。

caller

frag: 0040217B callers = [00402146;;]
lea ebx, dword[ebp+FFFFFECC]
push ebx
lea ebx, dword[ebp+FFFFFED0]
push ebx
lea ebx, dword[ebp+FFFFFF2C]
push ebx
lea ebx, dword[ebp+FFFFFE68]
push ebx
lea ebx, dword[ebp+FFFFFEFC]
push ebx
lea ebx, dword[ebp+FFFFFF74]
mov dword[ebx], esi
push ebx
lea ebx, dword[ebp+FFFFFCE8]
push ebx
lea ebx, dword[ebp+FFFFFF74]
mov dword[ebx], esi
push ebx
lea ebx, dword[ebp+FFFFFD5C]
push ebx
call 0040133C


callee

proc: 0040133C callers = [00401DD8;00401EE6;004021BE;0040232A;00402AAF;00402BD8;00402D01;;00402E2A;004030B7;004031E0;00403309;0040357B;
004036A4;004038FB;;]
frag: 0040133C callers = []
push ebp
mov ebp, esp
push ebx
push esi
push edi
sub esp, 05C
xor esi, esi
push esi
push esi
push esi
push esi
push esi
push esi
xor eax, eax
mov ebx, dword[ebp+1C]
movsx ecx, word[ebx]
mov ebx, dword[ebp+08]
sub ecx, dword[ebx+18]
shl ecx, 1
add ecx, dword[ebx]
movsx ecx, word[ecx]
cmp ecx, eax
jne 00401377
mov ebx, dword[ebp+28]
mov word[ebx], 0000
jmp 0040150E

2008年11月4日火曜日

だんだん濃くなってきたぞ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
そろそろ周辺調査から、目標に向かう作業にいったほうがよさそうだ。

アセンブラとPEフォーマットとマシン語の注入ってもう逝っちゃってますな。

「任意のプログラムを他プロセスへ注入する」そんなこと許しちゃだめでしょ> OS
もちろん「誰が注入する」かもありますが。

リバースエンジニアリング
64ビット環境でのリバースエンジニアリング

引数に関しては4つまでレジスタ、以後スタックという流れだが、call命令のリターン値については、スタックに積まれる。

ってこういうことを生成系無しでやるのか~ちょっとつらいかも。
32bitと64bitという違いはあるが、手練の視点がみれたのはいいことだ。


BASICからも機械語を呼び出せる
あああーーー、そうだ。Call by ValueなのかCall by Nameなのかもしらないなぁ、もとの処理系。頭痛い。

調査の続き

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Javaバイトコードをデコンパイルする効果的なアルゴリズム

制御フローをある程度調べる必要があるわけで、「ドミネータツリーを使った制御構造の復元を考えるにあたって、まずは、簡単にわかる情報をあげておきます。」とかのくだりは少しさんこうになるかな?しかし、吹き出しがぐしゃぐしゃに入っていて、ステップごと解説はよむことができない・・・。


書き手の癖や高級言語の性質がマシン語にでるならね。しかし元の言語の処理系が手に入らないと無理だな~。だってマシン語と制御構造の関係がまったく探れないので。x86はLoopとjumpがあるから、それに変換していてくれているならまあ、望みがないわけではないが。

Loopならloopかもしれないが、jumpもloopかもしれないがそうでないかもしれない。
おまけ程度ですな。

デコンパイル、リバースエンジニアリング

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
世の中、いろいろな人がいるものだ。


といっても,復元不可能とわかっている情報 (コメントやローカル変数名など)についてはスッパリあきらめて,復元可能な情報をいかに読みやすい形で表示するか (元通りでなくても読みやすければよい) という目標にすり替えます.

まさにそれなんだけど。今やろうとしている解析の対象のバイナリは、元の言語がCですらない。

解析としては、

  • 関数引数がわかる。

  • ループ変数がわかる。

  • 短絡評価を消すことができる


とかでもかなり大きい。fragmentをつなぎあわせるのが楽になるからだ。

すべてを解析したいわけではない(興味のあるのはアルゴリズムとかファイルフォーマットであるケースがほとんどのはず)ので、絞込みを効率化することも大事。
ジャンルによってはfloatがらみのコードが出てくる関数かどうかを判定するだけでも違う。普通はUIにはfloat演算は出てこないからだ(MacのQuartzは違うだろうが)。
ただ、GUIは普通、APIをCallするので、その周辺を捨てることはできる。逆にFile Formatはfileを読み書きするAPIから切り崩すことになる。

visualizing .asm with graphiviz

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
When you are tired, stop coding. Because you are getting no where.
If your head is clear, you get the clear ans.

def graphbuilder(t):
edge_list = []
for proc in t.findall('procedure'):
for frag in proc.findall('fragment'):
for op in frag.findall('op'):
operator = op.get('operator')
operand = op.get('operand')
if operator.startswith('call'):
if operand.startswith('dword'):
call_target = operand.rsplit(' ')[-1][:-1]
else:
call_target = operand
edge_list.append((proc.get('addr'), call_target))
return pydot.graph_from_edges(edge_list, directed=True)

pydot

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

edge_list = [
('0', '1a'),
('0', '2'),
('2', '1a'),
('2', '2'),
]
g = pydot.graph_from_edges(edge_list, directed=True)
g.write_raw('test.dot')

generates

digraph G {
0 -> "1a";
0 -> 2;
2 -> "1a";
2 -> 2;
}

2008年11月3日月曜日

graphivizで視覚化

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
.asmのreference関係を描画させてみたが、びみょ~。
生成されるグラフの縦横比が1:1000くらいで、全体図だとただの横線になっている。
レイアウトのエンジンをいじるか、捨象するようなことをしないとだめだ。スクロールもままならないし。

git-svn

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
git-cvsが気に入ったし、Gaucheをrpm化したいので、Gaucheをgit-svnして見ることにした。
git-svnがうまく動けば、いま使っているsubversionをやめてgitに代えよう。
そのかわりtracにgitプラグインをいれてgitに対応させる必要があるが。


git-svnとgit-importsvnは違うらしい。前者は双方向、後者はgit行きのみのようだ。gitとsvnを双方向でつなぐメリットは何だろう?

  • revision stampの問題

  • meta 構成管理

  • すでにsubversionを使っているプロジェクトで自分だけgitのlocal repositoryを持つ

アイディアを証明することと実用に耐えるものにすること

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
だいぶ差がある。

2:8の法則を使って説明すると、労力(コード、テスト量)の2割は前者、残りの8割は後者。
で、価値を感じる部分は使い始めるまでは、前者が8割、後者が2割。

「使い始める前」が味噌。いままでできなかったことを可能にすることによる価値は8割だといいたいところだが、微妙。もちろん作り始めるモチベーションはそのバランスじゃないと存在しないのですが。

使い始めて使いにくさを実感すると、実用に耐えるものにすることに価値を感じ始める。実用に耐える状態を維持する、つまりユーザの不快感を取り除く作業です。メンテナンスと呼ばれていますが、エレベーターとかのメンテナンスとかとはちがい、ソフトウェアのメンテナンスは、定期整備というよりむしろ建物のリフォームや改築といったほうがあたっている。

当然、リフォームや改築をするためには元の構造がよくないとだめでしょう。設計が悪いとリフォームや改築自体が不可能で、建て直しになってしまう。ソフトウェアも同じ。

結局、使うのをやめるまでにトータルの8割の労力を投じることになるだろう。よい設計、悪い設計があるとしたら、その労力を減らす点が上げられる。しかし所詮未来予知なので、完全にはできない。そこで使いながら作り変えていく形態が必然になる。

作り変えていく作業を行うと、当然その過程でbugが入ってサービスがとまる危険が常に付きまとう。となると、常にテストし続けることになる。テストのコストが高い、つまり自動化されていないということは、そのような形態を不可能にしてしまう。
No automated test, No evolutionである。

また、メンテナンスを常にし続けるという形態を考えると、頻繁にリフォームされる家というのは現実的には存在しなくて、むしろ生物のホメオスタシーや新陳代謝を想起するほうがよりよいだろう。

当たり前のことだが、人間は、生きている間に皮膚がない状態になったり、骨がない状態になったりはしない。機能停止状態がいない。80年間365日24時間無停止である。生きているとはそういうことである。心臓の筋細胞とて例外ではない。しかし心臓はとまることはない。

あるサイトを支えるプログラムがあるとしたら、とめずに置き換えていくことができることが大事で、生物のあり方を目指すべきだろう。サイトの機能が増えていく過程は、生物が発生して成長していく過程になぞらえてもいいだろう。

細胞は全部入れ替わるし、構成している分子も入れ替わる。機能も変わる(蝶を考えてみよう)。しかし同一の生き物であることにはかわりがない。サイトもそのようにあるべき。ウェブサイトのデザインといった場合、cssで見えがどうのこうのというのはごくごく小さな話で、ユーザにサービスを提供する生物を創造するつもりでデザインすべきだとおもう。
そのレベルから見た場合、アイディアというのは、羽をつけたら空を飛ぶことができそうだみたいな要素です。

飛んでいるトンボをみたらよくできているとおもうが、卵からヤゴになり、脱皮して飛べるようになるプロセスを支え続けるものはなにか?という命題はサイトを通じてサービスを提供するのなら考えざるを得ないのです。

2008年11月1日土曜日

parser for disassm output

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Use it as you like. This is BSD License.
It format output into html, with fragment jump for jump and call instructions.

import pprint
import re
import elementtree.ElementTree as ET

ASSEMBLY_START = '+++++++++++++++++++ ASSEMBLY CODE LISTING +++++++++++++++++++'
PROC_BOUNDARY = '========='
FRAG_BOUNDARY = '---------'
ASM_FORMAT = (r''':(?P[0-9A-Z]{8}) '''
'''(?P([0-9A-Z]{2})+)[ ]+'''
'''(?P[a-z]+)'''
'''( (?P([a-zA-Z0-9,+-<> ]|\[|\])+))?'''
)
asm_line = re.compile(ASM_FORMAT)

CROSS_REFERENCE_START = '*************** Cross Reference Listing ****************'
FRAG_LINE = r'--(?P[0-9A-Z]{8})::((?P[0-9A-Z]{8}),)+'
PROC_LINE = r'==(?P[0-9A-Z]{8})::((?P[0-9A-Z]{8}),)+'
CONT_LINE = r'[ ]+((?P[0-9A-Z]{8}),)+'


class Parser(object):
'''
>>> asm = file('hoge.asm', 'r')
>>> p = Parser()
>>> p.parse(asm)
>>> for n in p.assembly:
... print n, n.attrib['addr']

>>> print p.assembly[14][3], p.assembly[14][3].attrib['addr']
>>> for op in p.assembly[14][3]:
... print op, op.attrib['addr'], op.attrib['raw'], \
op.attrib['operator'],\
op.attrib['operand']
'''
def __init__(self):
self.current_parse = self.parse_something
self.prev_line = ''
self.assembly = ET.Element('program')
self.proc = ET.SubElement(self.assembly, 'procedure')
self.proc.attrib['addr'] = '0x0'
self.frag = ET.SubElement(self.proc, 'fragment')
self.frag.attrib['addr'] = '0x0'

def parse(self, f):
try:
for i, line in enumerate(f):
#pprint.pprint((i+1, line))
self.current_parse(line)
self.prev_line = line
except Exception, e:
print 'something wrong around line', i+1
pprint.pprint((i, self.prev_line))
pprint.pprint((i+1, line))
pprint.pprint(self.assembly)
pprint.pprint(self.proc)
pprint.pprint(self.frag)
raise e
def parse_assembly(self, line):
assert self.assembly is not None
if line.startswith(CROSS_REFERENCE_START):
print 'CROSS_REFERENCE_START'
self.current_parse = self.parse_reference
return
elif line.startswith(PROC_BOUNDARY):
self.proc = ET.SubElement(self.assembly, 'procedure')
assert self.proc is not None
self.frag = ET.SubElement(self.proc, 'fragment')
assert self.frag is not None
return
elif line.startswith(FRAG_BOUNDARY):
assert self.proc is not None
self.frag = ET.SubElement(self.proc, 'fragment')
assert self.frag is not None
return
else:
pass

for matchobj in asm_line.finditer(line):
d = matchobj.groupdict()
if 'line_addr' in d:
match = d['line_addr']
if self.prev_line.startswith(PROC_BOUNDARY):
assert self.proc is not None
self.proc.attrib['addr']= match

if self.prev_line.startswith(PROC_BOUNDARY) or \
self.prev_line.startswith(FRAG_BOUNDARY):
assert self.proc is not None
assert self.frag is not None
self.frag.attrib['addr']= match

op = ET.SubElement(self.frag, 'op')
op.attrib['addr'] = match
if 'raw_binary' in d:
op.attrib['raw'] = d['raw_binary']
if 'operator' in d:
op.attrib['operator'] = d['operator']
if 'operand' in d:
op.attrib['operand'] = d['operand']

def parse_reference(self, line):
pass

def parse_something(self, line):
if line.startswith(ASSEMBLY_START):
print 'ASSEMBLY_START'
self.current_parse = self.parse_assembly

class DocTree(object):
def __init__(self):
self.root = ET.Element('html')
assert self.root is not None
self.head = ET.SubElement(self.root, "head")
title = ET.SubElement(self.head, "title")
title.text = "formatted asm result"
self.body = ET.SubElement(self.root, 'body')
assert self.body is not None
def setcss(self, css):
e = ET.fromstring(css)
print 'using css'
print '-' * 20
print e
print e.text
print '-' * 20
self.head.append(e)

def html(self):
return ET.ElementTree(self.root)

css = '''
'''
class MakeHTMLVisit(object):
def __init__(self):
self.doc = DocTree()
self.doc.setcss(css)
assert self.doc.body is not None
self.current = self.doc.body
assert self.current is not None

def accept(self, e):
assert self.current is not None
parent = self.current
self.current = self.SubElement(parent, e)
for c in e:
self.accept(c)
self.current = parent

def SubElement(self, doc_parent, src_element):
assert doc_parent is not None
assert ET.iselement(doc_parent)
assert src_element is not None
assert ET.iselement(src_element)
e = ET.SubElement(doc_parent, 'div')
try:
self.decoreate(e, src_element)
except Exception, ex:
pprint.pprint(src_element)
raise ex
return e

def decoreate(self, e, src_element):
addr = src_element.get('addr')
if src_element.tag == 'procedure':
e.attrib['class'] = 'procedure'
e.text = 'proc: %s\n'%(addr)
elif src_element.tag == 'fragment':
e.attrib['class'] = 'fragment'
e.text = 'frag: %s\n'%(addr)
elif src_element.tag == 'op':
e.attrib['id'] = addr
e.attrib['class'] = 'op'
operator = src_element.get('operator', None)
operand = src_element.get('operand', None)
if 'j' in operator:
a = ET.SubElement(e, 'a', href='#%s'%(operand))
a.text = '%s %s\n'%(operator, operand)
elif operator.startswith('call'):
if operand.startswith('dword'):
html_frag = operand.rsplit(' ')[-1][:-1]
else:
html_frag = operand
a = ET.SubElement(e, 'a', href='#%s'%(html_frag))
a.text = '%s %s\n'%(operator, operand)
else:
e.text = '%s %s\n'%(operator, operand)
else:
pass

asm = file('hoge.asm', 'r')
p = Parser()
p.parse(asm)
visit = MakeHTMLVisit()
visit.accept(p.assembly)
html = visit.doc.html()
html.write("hoge.html")

もきゅ~。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

:0040110C 8B5D10 mov ebx, dword[ebp+10]
:0040110F 0303 add eax, dword[ebx]
:00401111 8B5D10 mov ebx, dword[ebp+10]
:00401114 8903 mov dword[ebx], eax
---------
:00401116 66FF4580 inc word[ebp-80]

のようなもの(disassemの出力)を食って

<Element procedure at 12aa4170> 00407BD9
<Element procedure at 12aa4680> 00407BEC
<Element fragment at 12614dd0> 00404A20
<Element op at 12614ea8> 00404A20 E806000000 call 00404A2B
<Element op at 12614f38> 00404A25 E87D000000 call 00404AA7
<Element op at 12614fc8> 00404A2A C3 ret None

を吐くものを作った。もう眠いです。
あす以降、このtreeをレンダリングするプログラムを書きます。
まあ、手でwikiに貼り付けるより、効率的だし、楽しいのだが。コードもそのうち公開します。

disassembleの結果でどこが大事かを追跡するのはフローグラフっぽいものを生成できないとつらいので。graphvizで絵でもだすか。ウィルスの解析結果出力みたいだな。

結局、コンピュータウイルスのコード静的解析による特徴抽出と分類とかとやろうとすることかわらないよな~。