There's an echo in my head

日々のメモ。

the pillows “RETURN TO THE THIRD MOVEMENT Vol.3” at 渋谷 duo MUSIC EXCHANGE

おっかなびっくりしながら行ってきた。本当にみんな元気でよかった。でも2時間近く立ってるのが大変になっちゃったんだよなあ。でもよかった。

さわおが肉体は衰えても、心はそれとは別に老いないようにしているというようなことを言っていて、そういうものかもなと思った。思考の出力方式としての体が衰えるから、それによって思考の幅が狭まることもあると思うけど、でもそればかりでもないのかもしれない。

いやでも今日は(といってもこれを書いているのは12月だけど)本当にみんな元気でよかった。

OpenSSL の -trace オプションを使って SSL/TLS のメッセージを観察する

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)

2020/12/25 Homecomings の BLANKET TOWN BLUES 日本橋三井ホールに行ってきた

もう1ヶ月以上前のことだけど、行ってきた。

当日は仕事で開演から20分ぐらい遅れて到着し、照明が明るくなって指定席に移動できるようになるまでの20分ぐらいは後ろの方で立って見ていた。

コロナ禍の中でライブに行くのは初めての体験で、入り口のところでまずは手をアルコール洗浄し、チケットも自分でもぎって差し出されるビニール袋に自分で入れる、会場内では演者以外が喋らず拍手のみで反応を返す、という徹底した状況だった。終演後も建物から出るまでほとんど会話がなかった。参加者としても徹底している。 ただ、MCの中で畳野さんが「みなさんにお知らせがあります」とメジャーデビューの話を予定より早く切り出そうとしてつっこまれていた時には、会場も声を出して笑っていた。

1年前の2019/12/22の PET MILK の際に福富さんが「世界が優しくなくなっている」と言っていたけど、今回は「優しくないニュースもあるけど、優しいニュースもある」というような話をしていて、ネガティブな状況のなかでもポジティブなところも見ようとしているのかなあと上から目線ながら感じた。

個人的にメジャーとインディーズの境界が曖昧になってきているので、メジャーデビューの話を聞いたときには「あっ、インディーズだったんだ」という気持ちだったけど、多分それは外にいるからで、中の人たちからしたらきっと嬉しいことだから、そう考えるとめでたい。

最初に演奏された Blue Hour がとても好きで、今回遅刻で生演奏を聴けなかったことが残念だったけど、でも帰宅してから配信で聴くことができた。感染症の蔓延自体はネガティブな出来事だけど、それが引き金となってこうやって新しい手段が増えること自体はとても嬉しい。

youtu.be

今ならライブのディレクターズカット版が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

screen で reattach しても ssh-agent が効き続けるようにする。

仙石浩明の日記: 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

参考

macOS をセットアップするときに設定しているもの

OS のバージョンによって変わっているかもしれない。

:memo: Sonoma 以降に対応した記事を書いた。

確認ダイアログのボタンを Tab キーで選択できるようにする

Preferences -> Keyboard -> Shortcuts -> Use keyboard navigation to move focus between controls

スクロールバーを常に表示する

System Preferences -> General

自動補正をだいたい無効化する

System Preferences -> Keyboard -> Text

同一アプリケーション内のウィンドウを Option+Tab で切り替える

System Preferences -> Keyboard -> Shortcuts -> Keyboard

Terminal.app のタブを Ctrl+Tab で切り替える

System Preferences -> Keyboard -> Shortcuts -> App Shortcuts

Select~ と Show~ の両方を設定しているのは、バージョン間のメニュー名の差異によるものだろうか。

Terminal.app からコピーするときに装飾を除外する

$ defaults write com.apple.Terminal CopyAttributesProfile com.apple.Terminal.no-attributes

Terminal.app でコマンド実行した行に角カッコが付かないようにする

$ defaults write com.apple.Terminal AutoMarkPromptLines -bool NO

https://apple.stackexchange.com/questions/209635/what-functionality-do-marks-offer-in-the-el-capitan-terminal

タイトルバーのファイル名をダブルクリックしたときにファイル名の変更をしない

$ defaults write -g ApplePersistence -bool no

Google Chrome.app でスワイプしたときにナヴィゲーションの操作をしない

$ defaults write com.google.Chrome AppleEnableSwipeNavigateWithScrolls -bool FALSE

円マークでバックスラッシュを入力する

  1. Input method の設定画面を開く
  2. 日本語入力の ¥ の入力でバックスラッシュを入力するよう選択する
  3. あわせて Input modes でローマ字にチェックを入れる
  4. そうすると Input method で ABC の項目がマイナスボタンで削除できるようになるので、削除する

https://materialsinformaticsbeginner.blogspot.com/2021/03/backslash-setting-bigsur.html

【追記】C と Go で for 文のループでのスタックフレームの積み方が違うという気付き → 変数の確保の方法が違うだけだった

この記事を読んでいて、不思議に感じたのでメモ。

blog.p1ass.com

というのも、 低レイヤを知りたい人のための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

言語仕様や吐き出されたアセンブリなどを読めば厳密なことがわかりそうだけど、とりあえずここまで。

追記 2020-06-14

アセンブリを読んでみた。結論から書くと、

  • C の場合、ループごとにスタックフレームを確保する(rbpを積む)ことはなく、同じスタックを使っている
  • Go の場合もループの実行ごとにスタックフレームを追加で積んでいることはない。その代わり、変数の宣言のたびにメモリ領域を確保しているような雰囲気。

スタックフレームの積み方については、そうでなきゃループ前に宣言されたローカル変数が読めなくなっちゃうので当然か。

C

直接アセンブリを書き出す。

$ 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

アセンブルした。

$ 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 5.x に更新する際に rails_kwargs_testing gem を使ったら便利だった

Rails 4.x で動いている社内ツールを Rails 5.x に更新する作業を最近やっていて、コントローラ・リクエスト周りのテストの書き換えに rails_kwargs_testing gem が便利だったのでメモ。

ざっくり書くと、これを使うと Rails 5.x 用のテストコードに寄せた状態で Rails 4.x 上でテストを実行できるようになるので、 BUNDLE_GEMFILERails 4.x と 5.x 用の Gemfile を指定することで両方を CI で走らせることが容易になる。詳細は作者である r7kamura さんのブログに書かれているので、そちらを参照してもらいたい。

r7kamura.com

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 を使うとテストコードの一括書き換えのもできて便利。

このブログに出てくるコードスニペッツは、引用あるいは断りがない限りMITライセンスです。