揮発性のメモ2

http://d.hatena.ne.jp/iww/

EUCに無い文字2

①②③、㌔㍉、㎞㎜ などは EUCJPに無い文字が EUCJP-MS, EUCJP-WIN にはある。
これらの文字を含んだテキストは iconv で変換可能

元テキスト

EUCJP⇒UTF8変換
iconv -c -f EUCJP -t utf8 /tmp/kishu.txt

EUCJP-WIN⇒UTF8変換
iconv -c -f EUCJP-WIN -t utf8 /tmp/kishu.txt

CP51932⇒UTF8変換

髙(はしご高)、﨑(たつ崎) などはEUCJP-WINには無いが CP51932 にはあるらしい。
iconvは CP51932 に未対応なので、PHPを使ってみる

#!/usr/bin/php -q
<?php

$euc = file_get_contents($argv[1]);
$utf8 = mb_convert_encoding($euc, "UTF-8", "CP51932");
print($utf8);

やったぜ

gccで、スレッド間で同じメモリを同時にアクセスしてる人を探してぶっ殺したい

gccで、スレッド間で同じメモリを同時にアクセスしてる人を探してぶっ殺したい。

そのためにはgccの TSAN(Thread Sanitizer)機能を使う

-fsanitize=thread

ソース
#include <pthread.h>
#include <stdio.h>

volatile long long A=0;

void *gettidtest( void *arg )
{
    int number = (int)(long) arg;
    long long i;

    printf("thread=%d start\n", number);
    for(i=0;i<1000000LL;i++){
        A++;     // 排他制御なし
//      __atomic_add_fetch( &A, 1, __ATOMIC_RELAXED );   // アトミック加算
    }
    printf("thread=%d end\n", number);

    return NULL;
}

int main( int argc, char **argv )
{
    int i;
    pthread_t p[10]={};

    for(i=0;i<10;i++){
        pthread_create( &p[i], NULL, gettidtest, (void*)(long)i );
    }
    for(i=0;i<10;i++){
        pthread_join( p[i], NULL );
    }
    printf("A=%lld\n",A);

    return 0;
}
コンパイル
$ gcc -g -fsanitize=thread thread.c
実行結果

競合したところを教えてくれる

問題点
  • 競合を発見しても終了しない
    -fno-sanitize-recover=all が効かず、検知後もプログラムは続行する
  • -fsanitize=address と一緒には使えない
    どちらか一方しか使えない
  • x86_64 でしかサポートしてない
    Cygwinもダメ、32bitもダメ、ARMもダメ
続きを読む

gccで、どんな最適化がかかっているかを見る

gcc -Q --help=optimizers

このコマンドで、どんなオプティマイズオプションがあるか、どれが有効になっているか を確認できる

$ gcc -Q --help=optimizers
The following options control optimizations:
  -O<number>
  -Ofast
  -Og
  -Os
  -Oz
  -faggressive-loop-optimizations       [enabled]
  -falign-functions                     [disabled]
  -falign-functions=
  -falign-jumps                         [disabled]
(後略)
-fno-omit-frame-pointer

レジスタEBPを汎用レジスタに使わせないように指示するオプション。
レジスタEBPは本来はスタック用のポインタだけど、-O2とかの最適化オプションを指定すると勝手に使いまわされちゃって、死んだときcore見てもうまくバックトレースできないことがあって嫌なので、それを抑止する

なにも指定しないとdisabled

$ gcc -Q --help=optimizers | grep omit
  -fomit-frame-pointer                  [disabled]

-O2をつけると自動でenabledになる

$ gcc -Q --help=optimizers -O2 | grep omit
  -fomit-frame-pointer                  [enabled]

-fno-omit-frame-pointer でdisabledにおさえつける

$ gcc -Q --help=optimizers -O2 -fno-omit-frame-pointer | grep omit
  -fomit-frame-pointer                  [disabled]

gccで、配列の範囲を超えてアクセスしてる人を探してぶっ殺したい

gccで、配列の範囲を超えてアクセスしてる人を探してぶっ殺したい。
そのためにはgccの ASAN(Address Sanitizer)機能を使う

-fsanitize=address

ソース
#include <stdio.h>
int main()
{
    char buf[15];

    printf("MAIN\n");
    for(int i=0; i<16; i++){
        printf("%08X:buf[%d]\n", &buf[i], i);
        buf[i] = i;
    }

    return 0;
}

配列が15個しかないのに16回まわるのではみ出る、というサンプルプログラム

コンパイル
gcc -g -fsanitize=address main.c

-gオプションは無くてもよいが、つけると検知時に行番号が表示されるのでつける

実行結果
MAIN
621FF520:buf[0]
621FF521:buf[1]
(中略)
621FF52E:buf[14]
621FF52F:buf[15]
=================================================================
==1594509==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd621ff52f at pc 0x55660474d2aa bp 0x7ffd621ff4e0 sp 0x7ffd621ff4d8
WRITE of size 1 at 0x7ffd621ff52f thread T0
    #0 0x55660474d2a9 in main /tmp/main.c:9
    #1 0x7f68a29f8189 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #2 0x7f68a29f8244 in __libc_start_main_impl ../csu/libc-start.c:381
    #3 0x55660474d0e0 in _start (/tmp/a.out+0x10e0)

Address 0x7ffd621ff52f is located in stack of thread T0 at offset 47 in frame
    #0 0x55660474d1b8 in main /tmp/main.c:3

  This frame has 1 object(s):
    [32, 47) 'buf' (line 4) <== Memory access at offset 47 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /tmp/main.c:9 in main

はみ出た時点でABORTする。 ちゃんと何行目ではみ出たかを検知している。
(はみ出なければ何も起きない)

-fsanitize=bounds

配列をはみ出たことだけを検知したいときは bounds を使う。
またこのときは ABORTせずに適当にごまかして先に進めてしまうので、それを回避したいときは
-fno-sanitize-recover=all オプションも指定すると、そこでプログラムが終了する。

コンパイル
gcc -g -fno-sanitize-recover=all -fsanitize=bounds main.c
実行結果
MAIN
9ED8575D:buf[0]
9ED8575E:buf[1]
(中略)
9ED8576B:buf[14]
9ED8576C:buf[15]
main.c:9:12: runtime error: index 15 out of bounds for type 'char [15]'

情報量が無いしcoreも吐けないので これはまあ使わない

コアダンプの設定

ABORTしたときにcoreを吐かせる方法。
まずそもそもulimitでコアが出るようにした上で、環境変数ASAN_OPTIONSでcoreを吐くように設定する

実行結果
$ ulimit -c unlimited
$ export ASAN_OPTIONS=abort_on_error=1:disable_coredump=0:unmap_shadow_on_exit=1

$ ./a.out
(中略)
==1594730==ABORTING
Aborted (core dumped)

吐かれたcoreには、はみ出しを検知してから実際にABORTするまでの間に ASANの関数がいっぱい挟まるので 解析利用時には最後の8~9層くらいは読み飛ばす

処理能力

3倍くらい遅くなる気がする

POSTFIXで、TLSで送信するよう設定

/etc/postfix/main.cf に次の設定を追記する

# ルート証明書のファイル指定
smtp_tls_CAfile = /etc/pki/tls/cert.pem

# TLS送信設定  may:可能であればTLSで送信
smtp_tls_security_level = may

# TLSログ設定  1:ログを残す
smtp_tls_loglevel = 1

chrootで、なんかシェルがおかしい

chrootしたとき、シェルがおかしいときがある

# chroot /data/chroot_hoge
\u@\h:\w$

ショボい環境でchrootするとだいたいこうなる。

chrootしたときに起動されるシェルは $SHELL なので、
シェルが/bin/shの環境から Debian環境のchrootを起動すると
/bin/sh ⇒ /bin/dash が起動されてしまう。

回避策は

1. /bin/bash を起動する

とくに差し支えなければこれで済む

# chroot /data/chroot_hoge /bin/bash
(chroot)root@hoge:/#

2. SHELL=/bin/bash

SHELLを書き換えてしまえば良いが、なんかちょっとキモい

# SHELL=/bin/bash chroot /data/chroot_hoge
(chroot)root@hoge:/#

Cygwinで、SDカードをext4でフォーマットする

Cygwinで、SDカードをext4でフォーマットする

準備

util-linux と e2fsprogs をインストールしておく

管理者権限で起動

Cygwinを管理者権限で起動する

フォーマット

/proc/partitions を見て、SDカードがどこにあるのかアタリをつける

$ cat /proc/partitions
major minor  #blocks  name   win-mounts

    8     0 234431064 sda
    8     1    562176 sda1
    8     2 233063146 sda2   C:\
    8     3    801792 sda3
    8    16 2930266584 sdb
    8    17     16384 sdb1
    8    18 2930248704 sdb2   D:\
    8    32 2930266583 sdc
    8    33    131072 sdc1
    8    34 2930134016 sdc2   E:\
    8    48   7879680 sdd
    8    49   7878656 sdd1   F:\


cfdiskの使い勝手は 普通のLinuxといっしょ
/sbin へのパスは通ってないので、フルパスで実行

$ /sbin/cfdisk /dev/sdd


mkfs.ext4の使い勝手は 普通のLinuxといっしょ
/usr/sbin へのパスは通ってないので、フルパスで実行

$ time /usr/sbin/mkfs.ext4 /dev/sdd1


Cygwinだけでext3のファイルシステムを作る その1 - 揮発性のメモ2