🐶

GitHub Actions でリークテスト:)

2021/12/02に公開

要約

Docker コンテナと Makefile を使ってローカルで行なっていた ValgrindSanitizers を用いたリークテストを,Github Actions を用いて,GitHub 上でも行えるようにした.このことにより,リークテストが容易になり,開発スピードが向上した.

序論

42Tokyo では,日々ピアラーニングと課題解決型学習を通して学習に励んでいます.何かを教えてくれる教師やメンターがいないので,自分たちで課題を理解し,問題点を見つけ,解決し,評価しています.評価を行うときには,評価項目に沿って,相手の課題を評価します.その際には,自分が今まで得た知識やテクを生かし,相手のコードのミステイクを見つけたり,コードがより良くなるためのアドバイスをしたり,されたり,議論したり,課題で問われている内容をきちんと理解し,自分で実装できているかを確認したりします.ここで,評価者が発見したフィックスできる,実装者が意図していない挙動ランタイムエラーリークセグフォは絶対に許容されません.これが曲者で,時間が経ってくると 42Tokyo 内で課題に対する知見が溜まっていき,コードを見る目がどんどん高度になり,課題をサクセスさせることが難しくなっていきます.知識が浅いままで実装をしていると,直ぐにエラーになってしまいますが,もう知り得たエラーパターンの漏れ発見などは煩わしくなってきます.
そこで,ローカルで Docker コンテナと Makefile を用いて行なっていた Valgrind と Sanitizer のリークテストを GitHub Actions を用いて,リポジトリにプッシュしたら自動で走るようにしました.
42 では,Build your own X の精神で,車輪の再発明をどんどん行なっているので,自分でリークチェッカー[1]などを実装できたら良かったのですが,今回は巨人の肩にたくさん乗らせてもらいオンラインでのリークテストを行うようにしました.

ローカルでのリークテスト

Docker コンテナ上で Makefile で設定したコマンドを実行し,リークテストを行なっています.

Valgrind リークテスト

  1. Valgrind をインストールした Dockerfile を書く.
    Dockerfile
    FROM ubuntu:20.04
    
    RUN apt-get update && \
        apt-get upgrade -y && \
        apt-get install -y build-essential valgrind && \
        rm -fr /var/lib/apt/lists/*
    
    WORKDIR /code
    
    CMD /bin/bash
    
  2. make valgrind を実行すると Valgrind テストが実行されるように Makefile を書く.
    Makefile
    .PHONY: valgrind
    valgrind: re
        valgrind --leak-check=full --show-leak-kinds=all --track-fds=yes ./$(NAME)
    
  3. 以下のコマンドを実行して,コンテナ上で Valgrind テストを実行する.
    Terminal
    docker build -t 42docker .
    docker run -it --rm -v $PWD:/code 42docker make valgrind
    

Sanitizer リークテスト

  1. gcc または clang をインストールした Dockerfile を書く.
    Dockerfile
    FROM ubuntu:20.04
    
    RUN apt-get update && \
        apt-get upgrade -y && \
        apt-get install -y build-essential clang && \
        rm -fr /var/lib/apt/lists/*
    
    WORKDIR /code
    
    CMD /bin/bash
    
  2. make leak, make address, make thread, make memory を実行するとそれぞれの Sanitizer テストが実行されるように Makefile を書く.
    Makefile
    CFLAGS    := -Wall -Wextra -Werror
    
    .PHONY: leak
    leak: CFLAGS += -g -fsanitize=leak
    leak: test
    
    .PHONY: address
    address: CFLAGS += -g -fsanitize=address
    address: test
    
    .PHONY: thread
    thread: CFLAGS += -g -fsanitize=thread
    thread: test
    
    .PHONY: memory
    memory: CFLAGS += -g -fsanitize=memory
    memory: test
    
    .PHONY: test
    test: re
        ./$(NAME)
    
  3. 以下のコマンドを実行して,コンテナ上で Sanitizer テストを実行する.
    Terminal
    docker build -t 42docker .
    docker run -it --rm -v $PWD:/code 42docker make leak
    docker run -it --rm -v $PWD:/code 42docker make address
    docker run -it --rm -v $PWD:/code 42docker make thread
    docker run -it --rm -v $PWD:/code 42docker make memory
    

オンラインでのリークテスト

Github Actions を用いて同様のリークテストができるようにします.ローカルで使用していた Makefile と同様のものを使って.

Valgrind リークテスト

CI 環境に直接 Valgrind をインストールする方法
  1. CI 環境に Valgrind をインストールする GitHub Action を書く.
    .github/workflows/valgrind.yml
    name: Valgrind
    on: [ push, pull_request ]
    
    jobs:
      Valgrind:
        runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: install valgrind
      run: |
        sudo apt update
        sudo apt install -y valgrind
      - name: Run Valgrind
      run: make valgrind
    
Docker containe action を用いる方法
  1. Github Actions 用の Valgrind をインストールした Dockerfile を書いて,dockerhub か ghcr に置く.
    Dockerfile
    FROM ubuntu:20.04
    
    RUN apt-get update && \
        apt-get upgrade -y &&  \
        apt-get install -y build-essential valgrind clang && \
        rm -fr /var/lib/apt/lists/*
    
    WORKDIR /code
    
    ENTRYPOINT ["valgrind --leak-check=full --show-leak-kinds=all ./a.out"]
    
  2. 上記を実行する Docker container action を書いて,マーケットプレイスに公開する.
    action.yml
    name: '42valgrind Leak checker'
    description: 'Run valgrind on ubuntu-latest'
    branding:
      icon: 'play-circle'
      color: 'green'
    
    inputs:
      flags:
        description: 'Flags passed to valgrind'
        required: true
        default: '.'
    
    runs:
      using: 'docker'
      image: 'docker://solareenlo/42valgrind:latest'
      entrypoint: /bin/bash
      args:
        - -c
        - ${{ inputs.flags }}
    
  3. 上記を実行する GitHub action を書く.
    .github/workflows/valgrind.yml
    name: Valgrind
    on: [ push, pull_request ]
    
    jobs:
      valgrind:
        runs-on: ubuntu-latest
    
        name: 42valgrind
        steps:
          - uses: actions/checkout@v2
          - name: 42valgrind Leak checker
            uses: solareenlo/42valgrind-action@v1.0.3
            with:
              flags: 'make valgrind'
    

Sanitizer リークテスト

  1. CI 環境に Sanitizers を実行する GitHub Action を書く.
    .github/workflows/sanitizers.yml
    name: Sanitizers
    on: [ push, pull_request ]
    
    jobs:
      Sanitizers:
        runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run Sanitizers
      run: |
        make leak
        make address
        make thread
        make memory
    

これでリポジトリにプッシュすると,Valgrind, Sanitizers のリークテストが自動で走るようになりました.(これらを使用したリポジトリ例:42ft_containers, 42CPP_Module_08_2021).

結論

  • オンラインでもリークテストができるようになり,便利かつ時短になって,大変満足だが,評価環境とリークテスト環境とに若干の差異があるので気を付ける.
  • reviewdog でリークテストのエラーが自動でプルリクされるようにする.
  • 他のテストもどんどん追加する.
  • こんな感じでいろんなことを自動化する.
  • もっと早くにやっておけば良かったです orz.

製作物

謝辞

オープンソースで,いろんな便利なツールが公開されていて,本当に感謝です.
42Tokyo では,個々人のペースで自由にいろんなことが勉強できて,本当に感謝です.
42Tokyo に関わる皆さんには,いろんなことを優しく教えてくださり,本当に感謝です.

脚注
  1. 例: leak_check_xmalloc, wraloc, 42_memleak_check, ft_mallocator ↩︎

GitHubで編集を提案

Discussion