おっかなびっくりしながら行ってきた。本当にみんな元気でよかった。でも2時間近く立ってるのが大変になっちゃったんだよなあ。でもよかった。
さわおが肉体は衰えても、心はそれとは別に老いないようにしているというようなことを言っていて、そういうものかもなと思った。思考の出力方式としての体が衰えるから、それによって思考の幅が狭まることもあると思うけど、でもそればかりでもないのかもしれない。
いやでも今日は(といってもこれを書いているのは12月だけど)本当にみんな元気でよかった。
おっかなびっくりしながら行ってきた。本当にみんな元気でよかった。でも2時間近く立ってるのが大変になっちゃったんだよなあ。でもよかった。
さわおが肉体は衰えても、心はそれとは別に老いないようにしているというようなことを言っていて、そういうものかもなと思った。思考の出力方式としての体が衰えるから、それによって思考の幅が狭まることもあると思うけど、でもそればかりでもないのかもしれない。
いやでも今日は(といってもこれを書いているのは12月だけど)本当にみんな元気でよかった。
openssl s_client コマンドの -trace
オプションを使うと SSL/TLS のメッセージを人間に優しい形でみることができる。
どういうメッセージが見られるかは OpenSSL with trace などで試すことができる。
ただ、リファレンスにある通り、このオプションは enable-ssl-trace
をつけてビルドをしないと利用できず、例えば apt で配布されているバイナリでは無効になっている。
なので、 Debian buster コンテナ上でのビルド方法をここにメモしておく。
$ docker run -it --rm buildpack-deps:buster bash root# cd /usr/local/src root# curl -O https://www.openssl.org/source/openssl-1.1.1d.tar.gz root# tar zxf openssl-1.1.1d.tar.gz root# cd openssl-1.1.1d root# ./config enable-ssl-trace && make && make install && make clean && ldconfig
こんな感じ。
root# openssl s_client -trace -connect google.com:443 -cipher "DEFAULT:@SECLEVEL=2" CONNECTED(00000003) Sent Record Header: Version = TLS 1.0 (0x301) Content Type = Handshake (22) Length = 301 ClientHello, Length=297 client_version=0x303 (TLS 1.2) Random: gmt_unix_time=0xBF8D65C0 random_bytes (len=28): (snip) session_id (len=32): (snip) cipher_suites (len=62) {0x13, 0x02} TLS_AES_256_GCM_SHA384 {0x13, 0x03} TLS_CHACHA20_POLY1305_SHA256 {0x13, 0x01} TLS_AES_128_GCM_SHA256 {0xC0, 0x2C} TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 {0xC0, 0x30} TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 {0x00, 0x9F} TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 {0xCC, 0xA9} TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 {0xCC, 0xA8} TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 {0xCC, 0xAA} TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 {0xC0, 0x2B} TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 {0xC0, 0x2F} TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 {0x00, 0x9E} TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 {0xC0, 0x24} TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 {0xC0, 0x28} TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 {0x00, 0x6B} TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 {0xC0, 0x23} TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 {0xC0, 0x27} TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 {0x00, 0x67} TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 {0xC0, 0x0A} TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA {0xC0, 0x14} TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA {0x00, 0x39} TLS_DHE_RSA_WITH_AES_256_CBC_SHA {0xC0, 0x09} TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA {0xC0, 0x13} TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA {0x00, 0x33} TLS_DHE_RSA_WITH_AES_128_CBC_SHA {0x00, 0x9D} TLS_RSA_WITH_AES_256_GCM_SHA384 {0x00, 0x9C} TLS_RSA_WITH_AES_128_GCM_SHA256 {0x00, 0x3D} TLS_RSA_WITH_AES_256_CBC_SHA256 {0x00, 0x3C} TLS_RSA_WITH_AES_128_CBC_SHA256 {0x00, 0x35} TLS_RSA_WITH_AES_256_CBC_SHA {0x00, 0x2F} TLS_RSA_WITH_AES_128_CBC_SHA {0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV compression_methods (len=1) No Compression (0x00) extensions, length = 162 extension_type=server_name(0), length=15 0000 - 00 0d 00 00 0a 67 6f 6f-67 6c 65 2e 63 6f 6d .....google.com extension_type=ec_point_formats(11), length=4 uncompressed (0) ansiX962_compressed_prime (1) ansiX962_compressed_char2 (2) extension_type=supported_groups(10), length=12 ecdh_x25519 (29) secp256r1 (P-256) (23) ecdh_x448 (30) secp521r1 (P-521) (25) secp384r1 (P-384) (24) extension_type=session_ticket(35), length=0 extension_type=encrypt_then_mac(22), length=0 extension_type=extended_master_secret(23), length=0 extension_type=signature_algorithms(13), length=42 ecdsa_secp256r1_sha256 (0x0403) ecdsa_secp384r1_sha384 (0x0503) ecdsa_secp521r1_sha512 (0x0603) ed25519 (0x0807) ed448 (0x0808) rsa_pss_pss_sha256 (0x0809) rsa_pss_pss_sha384 (0x080a) rsa_pss_pss_sha512 (0x080b) rsa_pss_rsae_sha256 (0x0804) rsa_pss_rsae_sha384 (0x0805) rsa_pss_rsae_sha512 (0x0806) rsa_pkcs1_sha256 (0x0401) rsa_pkcs1_sha384 (0x0501) rsa_pkcs1_sha512 (0x0601) ecdsa_sha224 (0x0303) rsa_pkcs1_sha224 (0x0301) dsa_sha224 (0x0302) dsa_sha256 (0x0402) dsa_sha384 (0x0502) dsa_sha512 (0x0602) extension_type=supported_versions(43), length=9 TLS 1.3 (772) TLS 1.2 (771) TLS 1.1 (770) TLS 1.0 (769) extension_type=psk_key_exchange_modes(45), length=2 psk_dhe_ke (1) extension_type=key_share(51), length=38 NamedGroup: ecdh_x25519 (29) key_exchange: (len=32): (snip) Received Record Header: Version = TLS 1.2 (0x303) Content Type = Handshake (22) Length = 122 ServerHello, Length=118 server_version=0x303 (TLS 1.2) Random: gmt_unix_time=0x142E888C random_bytes (len=28): (snip) session_id (len=32): (snip) cipher_suite {0x13, 0x02} TLS_AES_256_GCM_SHA384 compression_method: No Compression (0x00) extensions, length = 46 extension_type=key_share(51), length=36 NamedGroup: ecdh_x25519 (29) key_exchange: (len=32): (snip) extension_type=supported_versions(43), length=2 TLS 1.3 (772) (snip)
もう1ヶ月以上前のことだけど、行ってきた。
当日は仕事で開演から20分ぐらい遅れて到着し、照明が明るくなって指定席に移動できるようになるまでの20分ぐらいは後ろの方で立って見ていた。
コロナ禍の中でライブに行くのは初めての体験で、入り口のところでまずは手をアルコール洗浄し、チケットも自分でもぎって差し出されるビニール袋に自分で入れる、会場内では演者以外が喋らず拍手のみで反応を返す、という徹底した状況だった。終演後も建物から出るまでほとんど会話がなかった。参加者としても徹底している。 ただ、MCの中で畳野さんが「みなさんにお知らせがあります」とメジャーデビューの話を予定より早く切り出そうとしてつっこまれていた時には、会場も声を出して笑っていた。
1年前の2019/12/22の PET MILK の際に福富さんが「世界が優しくなくなっている」と言っていたけど、今回は「優しくないニュースもあるけど、優しいニュースもある」というような話をしていて、ネガティブな状況のなかでもポジティブなところも見ようとしているのかなあと上から目線ながら感じた。
個人的にメジャーとインディーズの境界が曖昧になってきているので、メジャーデビューの話を聞いたときには「あっ、インディーズだったんだ」という気持ちだったけど、多分それは外にいるからで、中の人たちからしたらきっと嬉しいことだから、そう考えるとめでたい。
最初に演奏された Blue Hour がとても好きで、今回遅刻で生演奏を聴けなかったことが残念だったけど、でも帰宅してから配信で聴くことができた。感染症の蔓延自体はネガティブな出来事だけど、それが引き金となってこうやって新しい手段が増えること自体はとても嬉しい。
今ならライブのディレクターズカット版が1500円というお手頃価格で配信されているのでこちらもお勧めである。 https://t.pia.jp/pia/ticketInformation.do?eventCd=2031028&rlsCd=001&lotRlsCd
Yahoo!ニュースより抜粋。
01. Corridor(to blue hour) 02. Blue Hour 03. Hull Down 04. Lighthouse Melodies 05. Smoke 06. Living Life 07. ANOTHER NEW YEAR 08. LEMON SOUNDS 09. HURTS 10. Special Today 11. Have Yourself A Merry Little Christmas 12. Moving Day Part1 13. Continue 14. PLAY YARD SYMPHONY 15. Cakes 16. Songbirds <アンコール> 17. Whale Living <ダブルアンコール> 18. Pedal 19. I Want You Back
仙石浩明の日記: ssh-agent を screen の中から使う方法 に書かれているように、 screen のなかで ssh-agent を使うにはちょっと一手間がいる。この中の環境変数 $SSH_AUTH_SOCK
を毎回書き換える処理が、 OpenSSH 7.3 から導入された IdentityAgent を使うことで不要になっていたのでメモ。
なお、以下は全て screen を実行するリモートホスト側での作業になる。
まず ssh ログイン時に実行される ~/.ssh/rc で、 $SSH_AUTH_SOCK
を元にシンボリックリンクを作る処理を入れる。これは従来と同じで、 ssh-agent のソケットファイルを同一のパスで指定できるようにするための対応である。
#!/bin/bash # Fix SSH auth socket location so agent forwarding works within tmux/screen if [ "$SSH_AUTH_SOCK" ]; then ln -sf $SSH_AUTH_SOCK ~/.ssh/agent.sock fi
そして ~/.ssh/config で IdentityAgent
にこのシンボリックリンクを指定する。
Host * IdentityAgent ~/.ssh/agent.sock
OS のバージョンによって変わっているかもしれない。
:memo: Sonoma 以降に対応した記事を書いた。
Preferences -> Keyboard -> Shortcuts -> Use keyboard navigation to move focus between controls
System Preferences -> General
System Preferences -> Keyboard -> Text
System Preferences -> Keyboard -> Shortcuts -> Keyboard
System Preferences -> Keyboard -> Shortcuts -> App Shortcuts
Select~ と Show~ の両方を設定しているのは、バージョン間のメニュー名の差異によるものだろうか。
$ defaults write com.apple.Terminal CopyAttributesProfile com.apple.Terminal.no-attributes
$ defaults write com.apple.Terminal AutoMarkPromptLines -bool NO
$ defaults write -g ApplePersistence -bool no
$ defaults write com.google.Chrome AppleEnableSwipeNavigateWithScrolls -bool FALSE
https://materialsinformaticsbeginner.blogspot.com/2021/03/backslash-setting-bigsur.html
この記事を読んでいて、不思議に感じたのでメモ。
というのも、 低レイヤを知りたい人のためのCコンパイラ作成入門 を読みながら for 文を作っていたときにループごとにスタックフレームを新しく積むことはなかったので、別の変数に再代入しただけで結果が変わることに違和感を覚えた。もしかして C と Go で扱いが違うのかもと思って、ループ変数とループ内で宣言した変数のアドレスを書き出してみた。
C の場合はループ変数もループ内で宣言した変数もアドレスは毎回一致していた。ということは、毎回同じスタック領域をスタックフレームを使っていることになる。( for の初期化文などと同じフレームかまではわからないけど、 for 文のあとで i
を参照することができないことを考えると、 for 文に入ったところで新しく積んでいるのかもしれない)
$ cat <<"EOF" >main.c #include <stdio.h> int main(int argc, char **argv) { for (int i = 0; i < 4; i++) { int j = i; printf("&i = %p, &j = %p\n", &i, &j); } return 0; } EOF $ gcc main.c && ./a.out &i = 0x7ffeec76353c, &j = 0x7ffeec763538 &i = 0x7ffeec76353c, &j = 0x7ffeec763538 &i = 0x7ffeec76353c, &j = 0x7ffeec763538 &i = 0x7ffeec76353c, &j = 0x7ffeec763538
Go の場合はループ変数のアドレスは同じだけど、ループ内で宣言した変数のアドレスは毎回変わっていた。ということは、ループ変数とは別に、ループの実行ごとにスタックフレームを追加で積んでいる…?
$ cat <<"EOF" > main.go package main import "fmt" func main() { for i := 0; i < 4; i++ { j := i fmt.Printf("&i = %p, &j = %p\n", &i, &j) } } EOF $ go run main.go &i = 0xc00012a008, &j = 0xc00012a010 &i = 0xc00012a008, &j = 0xc00012a020 &i = 0xc00012a008, &j = 0xc00012a028 &i = 0xc00012a008, &j = 0xc00012a030
言語仕様や吐き出されたアセンブリなどを読めば厳密なことがわかりそうだけど、とりあえずここまで。
アセンブリを読んでみた。結論から書くと、
スタックフレームの積み方については、そうでなきゃループ前に宣言されたローカル変数が読めなくなっちゃうので当然か。
直接アセンブリを書き出す。
$ gcc -S -masm=intel -O0 main.c
結果はこの gist に貼った。 https://gist.github.com/a2ikm/04299c9d37c5b45edd1801825eec3041
メタデータっぽいものを削った main.s をみると、rbp を操作しているのは最初の1回だけなのでスタックフレームがループごとに積まれているということもない。
また、 printf の引数をみると &i
に相当する -4[rbp]
と &j
に相当する -8[rbp]
が渡されていることから、毎回同じ変数を参照していることがわかる。
main: .LFB0: push rbp mov rbp, rsp sub rsp, 32 mov DWORD PTR -20[rbp], edi mov QWORD PTR -32[rbp], rsi mov DWORD PTR -4[rbp], 0 jmp .L2 .L3: mov eax, DWORD PTR -4[rbp] mov DWORD PTR -8[rbp], eax lea rdx, -8[rbp] lea rax, -4[rbp] mov rsi, rax lea rdi, .LC0[rip] mov eax, 0 call printf@PLT mov eax, DWORD PTR -4[rbp] add eax, 1 mov DWORD PTR -4[rbp], eax .L2: mov eax, DWORD PTR -4[rbp] cmp eax, 3 jle .L3 mov eax, 0 leave ret
逆アセンブルした。
$ go build -gcflags '-N -l' main.go $ objdump -M intel -d main > main.s
-N
と -l
はそれぞれ最適化とインライン化を行わないための go tool compile
コマンドのオプション。また、 go tool compile -N -l-S main.go
でも直接アセンブリを書き出すことができるようだけど、見慣れない AT&T syntax で読みづらかったのでこうした。
結果はこの gist に貼った。実行ファイル全体なのでデカい。 https://gist.github.com/a2ikm/bdd977b0381d0874bed89c313cd6ee1d
{パッケージ名}.{関数名}
がそのまま記録されているので main 関数の位置はすぐわかる。
0000000000492fe0 <main.main>:
ここでも rbp の操作をしているのは最初の1回だけなので、ループごとにスタックフレームを追加していることは無い。
493007: 48 8d ac 24 a0 00 00 lea rbp,[rsp+0xa0]
変数 i
を定義しているのはこの辺。cmp
で4と比較しているあたりから目星がつけられる。
49300f: 48 8d 05 ca e3 00 00 lea rax,[rip+0xe3ca] # 4a13e0 <type.*+0xd3e0> 493016: 48 89 04 24 mov QWORD PTR [rsp],rax 49301a: e8 91 8b f7 ff call 40bbb0 <runtime.newobject> 49301f: 48 8b 44 24 08 mov rax,QWORD PTR [rsp+0x8] 493024: 48 89 44 24 60 mov QWORD PTR [rsp+0x60],rax 493029: 48 c7 00 00 00 00 00 mov QWORD PTR [rax],0x0 493030: eb 00 jmp 493032 <main.main+0x52> 493032: 48 8b 44 24 60 mov rax,QWORD PTR [rsp+0x60] 493037: 48 83 38 04 cmp QWORD PTR [rax],0x4 49303b: 7c 05 jl 493042 <main.main+0x62> 49303d: e9 07 01 00 00 jmp 493149 <main.main+0x169>
名前からして怪しそうな runtime.newobject を覗いてみる。
000000000040bbb0 <runtime.newobject>: 40bbb0: 64 48 8b 0c 25 f8 ff mov rcx,QWORD PTR fs:0xfffffffffffffff8 40bbb7: ff ff 40bbb9: 48 3b 61 10 cmp rsp,QWORD PTR [rcx+0x10] 40bbbd: 76 3d jbe 40bbfc <runtime.newobject+0x4c> 40bbbf: 48 83 ec 28 sub rsp,0x28 40bbc3: 48 89 6c 24 20 mov QWORD PTR [rsp+0x20],rbp 40bbc8: 48 8d 6c 24 20 lea rbp,[rsp+0x20] 40bbcd: 48 8b 44 24 30 mov rax,QWORD PTR [rsp+0x30] 40bbd2: 48 8b 08 mov rcx,QWORD PTR [rax] 40bbd5: 48 89 0c 24 mov QWORD PTR [rsp],rcx 40bbd9: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax 40bbde: c6 44 24 10 01 mov BYTE PTR [rsp+0x10],0x1 40bbe3: e8 78 f4 ff ff call 40b060 <runtime.mallocgc> 40bbe8: 48 8b 44 24 18 mov rax,QWORD PTR [rsp+0x18] 40bbed: 48 89 44 24 38 mov QWORD PTR [rsp+0x38],rax 40bbf2: 48 8b 6c 24 20 mov rbp,QWORD PTR [rsp+0x20] 40bbf7: 48 83 c4 28 add rsp,0x28 40bbfb: c3 ret 40bbfc: e8 6f e1 04 00 call 459d70 <runtime.morestack_noctxt> 40bc01: eb ad jmp 40bbb0 <runtime.newobject>
この中で呼ばれている runtime.mallocgc はまさに変数領域を確保するための関数。したがって、スタックが積まれるとかではなくて、 j := i
で変数が宣言されるたびに領域が確保されているために毎回アドレスが変わっているのではないかと。
この関数名でググった結果、 https://medium.com/a-journey-with-go/go-memory-management-and-allocation-a7396d430f44 などが詳しそう。
Rails 4.x で動いている社内ツールを Rails 5.x に更新する作業を最近やっていて、コントローラ・リクエスト周りのテストの書き換えに rails_kwargs_testing gem が便利だったのでメモ。
ざっくり書くと、これを使うと Rails 5.x 用のテストコードに寄せた状態で Rails 4.x 上でテストを実行できるようになるので、 BUNDLE_GEMFILE
で Rails 4.x と 5.x 用の Gemfile を指定することで両方を CI で走らせることが容易になる。詳細は作者である r7kamura さんのブログに書かれているので、そちらを参照してもらいたい。
rspec の場合の tips として、テストファイルごとの describe
ブロックで prepend
するのではなく、 controller spec や request spec で指定されている :type
メタデータを使うことでまとめて prepend
することができる。
# spec/rails_helper.rb や spec/supports/rails_kwargs_testing.rb みたいなファイル if defined?(RailsKwargsTesting) RSpec.configure do |config| config.prepend RailsKwargsTesting::ControllerMethods, type: :controller config.prepend RailsKwargsTesting::RequestMethods, type: :request end end
Minitest を使っている場合も、ちょっと手間だけど、 ActionController::TestCase
を継承した共通のクラスを介することで同じようにまとめて対応することができる。こうしておけば、あとから rails_kwargs_testing gem を完全に消すことになったときにも手間が少ない。
なお、上記の記事で紹介されている rails5-spec-converter gem を使うとテストコードの一括書き換えのもできて便利。