Skip to content

fix: git wrapper to strip apm LD_LIBRARY_PATH pollution (Linux)#2

Merged
mincemaker merged 1 commit into
mainfrom
fix/apm-git-wrapper
May 24, 2026
Merged

fix: git wrapper to strip apm LD_LIBRARY_PATH pollution (Linux)#2
mincemaker merged 1 commit into
mainfrom
fix/apm-git-wrapper

Conversation

@mincemaker

@mincemaker mincemaker commented May 24, 2026

Copy link
Copy Markdown
Owner

問題

apm v0.14.2 (5fd0678) + git 2.54.0 の環境で apm install -g がサブディレクトリ依存のインストール時に常に失敗する。macOS では再現しない。

git clone --local --shared --no-checkout <bare> <consumer>
→ exit status 128

原因

apm PR #1436 が git clone --local --shared を導入した

2026-05-21 にマージされた microsoft/apm#1436 (perf(#1433): sparse-cone consumer materialization for subdir deps) が、サブディレクトリ依存のインストールに sparse-cone materialization を導入した。この最適化で bare_cache.materialize_from_bare()git clone --local --shared --no-checkout <bare> <consumer> を呼ぶようになった。

partial bare clone では upload-pack にフォールバックする

git clone --local --shared はソースリポジトリが partial clone (--filter=blob:none) の場合、upload-pack protocol にフォールバックし、git が内部で次を spawn する:

/bin/sh -c "git-upload-pack '/path/to/bare'"

apm (PyInstaller) が LD_LIBRARY_PATH を汚染している

apm は PyInstaller でビルドされたバイナリとして配布されている。PyInstaller のブートローダーは起動時にバンドルライブラリを読み込ませるため、プロセス環境に次を設定する:

LD_LIBRARY_PATH=/usr/local/lib/apm/_internal:...

/usr/local/lib/apm/_internal/ には libreadline.so.8 (336KB) が含まれているが、これはシステムの bash が要求するものより古く rl_print_keybinding シンボルが存在しない。

git_subprocess_env() が LD_LIBRARY_PATH を strip しない

src/apm_cli/utils/git_env.pygit_subprocess_env()GIT_DIR 等の git 系変数を strip するが、LD_LIBRARY_PATH は strip しない。そのため git subprocess は汚染された LD_LIBRARY_PATH を継承する。

bash が起動時にクラッシュする

このマシンの /bin/sh は bash で、libreadline.so.8 に動的リンクしている。汚染された LD_LIBRARY_PATH を持つ環境で bash が起動すると:

/bin/sh: symbol lookup error: /bin/sh: undefined symbol: rl_print_keybinding

bash が即クラッシュし、git clone が exit 128 で失敗する。

シェルスクリプトのラッパーでは直せない

ラッパー自体の起動にも /bin/sh (bash) が使われるため、同じ理由でクラッシュする。

対処 (暫定モンキーパッチ)

~/.local/bin/git に C バイナリのラッパーを置く。~/.local/bin は PATH で /usr/bin より前にあり、apm の shutil.which("git") がこのラッパーを先に発見する。

// dot_local/src/git-wrapper.c
int main(int argc, char *argv[]) {
    char *ld = getenv("LD_LIBRARY_PATH");
    if (ld && strstr(ld, "/apm/_internal"))
        unsetenv("LD_LIBRARY_PATH");
    execv("/usr/bin/git", argv);
    return 127;
}

/apm/_internal が含まれる場合のみ LD_LIBRARY_PATH を除去し、実 git を exec() する。apm 以外の通常の git 操作では何も変更しない。

chezmoi の run_onchange_ スクリプトで C ソースから自動ビルド。ソース変更時は chezmoi apply で再ビルドされる。Linux 専用 ({{ if eq .chezmoi.os "linux" }})。

撤去条件

microsoft/apm upstream が src/apm_cli/utils/git_env.pygit_subprocess_env()LD_LIBRARY_PATH を strip するよう修正した場合、または PyInstaller による配布をやめた場合。

確認方法:

rm ~/.local/bin/git
apm install -g  # 通れば撤去可

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant