Skip to content

Conversation

@DennisDyallo
Copy link
Collaborator

test claude

claude and others added 3 commits November 5, 2025 20:34
Modified the GitHub Actions workflow to use Zig compiler instead of the
default Ubuntu 24.04 gcc/g++ for Linux builds (both amd64 and arm64).

Key changes:
- Install Zig 0.13.0 on Ubuntu 24.04 runners
- Create wrapper scripts for zig cc/c++ targeting glibc 2.28:
  * x86_64-linux-gnu.2.28 for AMD64 builds
  * aarch64-linux-gnu.2.28 for ARM64 builds
- Set CC/CXX environment variables to use Zig wrappers
- Update ARM64 CMake toolchain to respect CC/CXX environment variables

Benefits:
- Better compatibility with older Linux distributions (glibc 2.28+)
- Zig provides hermetic cross-compilation without needing system toolchains
- Consistent glibc target across different build environments

The ARM64 toolchain now checks for CC/CXX environment variables first,
falling back to traditional aarch64-linux-gnu-gcc if not set, ensuring
backward compatibility with existing build processes.
Added test scripts and documentation to verify that NativeShims
compiled with Zig actually targets glibc 2.28 and works on older
Linux distributions.

Test scripts:
- test-glibc-compatibility.sh: Quick check of glibc symbol versions
- test-runtime-compatibility.sh: Full Docker-based runtime test
- TESTING.md: Complete testing documentation

These tools help validate that issue #334 is properly resolved by
ensuring the compiled library actually works on systems with glibc 2.28.
Added comprehensive test report documenting the validation of
NativeShims binaries compiled with Zig targeting glibc 2.28.

Key findings:
- x64 binary requires glibc 2.25 (better than 2.28 target)
- ARM64 binary requires glibc 2.25 (better than 2.28 target)
- Both binaries pass all compatibility checks
- Resolves issue #334 (reduced from glibc 2.38 to 2.25)

The report includes:
- Detailed methodology using readelf/objdump analysis
- Complete test results for both architectures
- Symbol version distribution analysis
- Distribution compatibility matrix
- Technical background on glibc versioning

Also fixed bugs in test-glibc-compatibility.sh that were discovered
during verification review.
@DennisDyallo

This comment was marked as outdated.

@claude

This comment was marked as outdated.

… compatibility check

- Replaced Ubuntu-specific .NET 6 installation steps with Microsoft's universal install script for broader compatibility.
- Removed CentOS 8 runtime compatibility test due to RHEL/CentOS package manager differences.
- Updated test outcome messaging to reflect Debian-based system focus and RHEL/CentOS testing requirements.
@DennisDyallo

This comment was marked as outdated.

@claude
Copy link

claude bot commented Nov 6, 2025

Claude finished @DennisDyallo's task —— View job


Code Review Complete

I've thoroughly reviewed this PR that introduces Zig-based compilation for NativeShims targeting glibc 2.28. Here's my comprehensive analysis:


Overview

This PR successfully addresses issue #334 by using Zig as a drop-in C/C++ compiler replacement to target glibc 2.28, dramatically improving Linux compatibility from requiring glibc 2.38 down to 2.25. The approach is sound and well-documented.


1. TEST-REPORT.md - Assessment: Excellent

Strengths

  • Comprehensive and well-structured: The report follows proper technical documentation standards with clear sections, methodology, results, and analysis
  • Accurate technical content: The glibc versioning explanation is correct - Zig targets act as upper bounds, and the linker selects the oldest compatible symbol versions
  • Excellent verification approach: Using readelf and objdump for static analysis is the correct approach for glibc compatibility verification
  • Clear distribution compatibility matrix: Shows exactly which distributions are supported (Ubuntu 18.04+, Debian 10+, RHEL 8+, etc.)
  • Professional presentation: Well-formatted with clear results, symbol distribution, and comparisons

Minor Suggestions

  1. Date discrepancy (line 3): The report shows "November 6, 2025" but we're in 2025. This should be corrected if it's meant to be a past date, or clarified if it's intentional.
  2. Consider adding: A brief note about why glibc 2.25 was the actual result (likely the getrandom() syscall wrapper added in glibc 2.25) would add educational value.

Soundness: Very Sound

The technical analysis is accurate. The symbol versioning approach is correct, and the conclusions are well-supported by the data.


2. TESTING.md - Assessment: Very Good

Strengths

  • Clear instructions: Easy to follow for developers at different skill levels
  • Multiple testing approaches: Provides both quick static analysis and comprehensive Docker-based runtime testing
  • Good troubleshooting section: Addresses common issues developers might encounter
  • Proper expectations set: Clearly shows expected output and what success/failure looks like

Issues to Address

Critical Issue: Ubuntu 18.04 glibc Version (line 64, 117)

- Ubuntu 18.04+ (glibc 2.27)

Problem: Ubuntu 18.04 actually has glibc 2.27, but the test report shows the binaries require glibc 2.25. While this means the library WILL work on Ubuntu 18.04, the documentation here is slightly misleading when it says "requires 2.28" in line 60.

Fix: The expected output section should be updated to reflect the actual results from the test report:

  • Maximum GLIBC required: 2.25 (not 2.28)
  • Update line 117 to note that if MAX_GLIBC is 2.25, then Ubuntu 18.04 is compatible

Moderate Issue: Incomplete Example Output (lines 24-68)

The example output shows "Maximum GLIBC required: 2.28" but the actual test report shows 2.25. This creates confusion.

Recommendation: Update the example to show 2.25 as the maximum version to match reality.


3. test-glibc-compatibility.sh - Assessment: Robust

Strengths

  • Proper error handling: Uses set -e and validates input
  • Comprehensive checks: Validates ELF format, extracts versions, checks for suspicious symbols, lists dependencies
  • Good user experience: Color-coded output, clear success/failure indicators
  • Correct version comparison: Uses sort -V for proper version sorting (2.28 > 2.3, etc.)

Issues to Address

Critical Issue: Version Comparison Logic (lines 66-76, 112-130)

if [ "$(printf '%s\n' "$MAX_GLIBC" "2.28" | sort -V | tail -n1)" = "2.28" ]; then

Problem: This comparison checks if MAX_GLIBC ≤ 2.28, which is correct. However, the error messages and success logic could be clearer.

Specific Issue (lines 67-68):

if [ "$MAX_GLIBC" = "2.28" ]; then
    echo -e "${GREEN}✓ Requires exactly GLIBC 2.28${NC}"

This branch will rarely trigger since the actual requirement is 2.25. The message "Requires exactly GLIBC 2.28" is also misleading - it suggests this is a good thing, but it's actually less compatible than requiring 2.25.

Recommendation: Simplify the logic:

if [ "$(printf '%s\n' "$MAX_GLIBC" "2.28" | sort -V | tail -n1)" = "2.28" ]; then
    echo -e "${GREEN}✓ Compatible with GLIBC 2.28+ (requires $MAX_GLIBC)${NC}"
else
    # MAX_GLIBC > 2.28
    echo -e "${RED}✗ Requires GLIBC $MAX_GLIBC which is newer than 2.28${NC}"
    exit 1
fi

Moderate Issue: Distribution List Accuracy (lines 115-123)

The script checks if MAX_GLIBC ≤ 2.27 before listing Ubuntu 18.04, but should check if MAX_GLIBC ≤ 2.27:

if [ "$(printf '%s\n' "$MAX_GLIBC" "2.27" | sort -V | tail -n1)" = "2.27" ]; then
    echo "  - Ubuntu 18.04+ (glibc 2.27)"
fi

This logic is correct ✅ but the subsequent distributions should also be conditionally listed based on their glibc versions for accuracy.

Minor Issue: Unclear Grep Pattern (line 94)

SUSPICIOUS_SYMBOLS=$(objdump -T "$LIBRARY_PATH" | grep -E "GLIBC_2\.(29|[3-9][0-9])" || true)

Suggestion: Add a comment explaining this regex detects glibc 2.29+ (2.29, 2.30-2.99, 2.300+):

# Check for glibc 2.29+ symbols (2.29, 2.30-2.99, etc.)
SUSPICIOUS_SYMBOLS=$(objdump -T "$LIBRARY_PATH" | grep -E "GLIBC_2\.(29|[3-9][0-9])" || true)

4. test-runtime-compatibility.sh - Assessment: Well-Designed

Strengths

  • Comprehensive end-to-end testing: Creates actual .NET app that loads the library
  • Multiple distribution testing: Tests on Ubuntu 18.04, 20.04, and Debian 10
  • Proper cleanup: Uses trap to clean up temporary files
  • Good error handling: Validates input and provides clear failure messages

Issues to Address

Critical Issue: .NET Installation Method (lines 138-144)

RUN apt-get update && apt-get install -y wget ca-certificates && \
    wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh && \
    chmod +x dotnet-install.sh && \
    ./dotnet-install.sh --channel 6.0 --install-dir /usr/share/dotnet && \
    ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet

Problem: According to the CLAUDE.md file in this repository (lines 383-384 in my analysis), there was a recent update to use a universal .NET 6 install script. The PR commit message even mentions "update: switch to universal .NET 6 install script and remove CentOS 8 compatibility check".

Impact: The current Dockerfile might fail on some distributions or use an outdated installation method.

Recommendation: Verify that this installation method works across all target distributions, or align with the changes mentioned in recent commits.

Moderate Issue: Missing libpcsclite Dependency

The test program tries to load NativeShims, which depends on libpcsclite.so.1 (as shown in both the test report and the static analysis). However, the Dockerfile doesn't install pcsclite.

Fix: Add pcsclite installation:

RUN apt-get update && apt-get install -y wget ca-certificates libpcsclite-dev && \

Moderate Issue: P/Invoke Function Selection (line 68)

[DllImport("libYubico.NativeShims.so", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Native_BN_new();

Concern: This assumes Native_BN_new() exists and is exported. If this function doesn't exist or the signature is wrong, the test will fail even if the glibc compatibility is correct.

Recommendation:

  1. Add a comment explaining which NativeShims function this corresponds to
  2. Consider using dlopen()/dlsym() from libc instead of P/Invoke to catch loading errors separately from symbol resolution errors

Minor Issue: CentOS 8 Removed from Tests (line 165-169)

The test images array doesn't include CentOS 8, but the report and TESTING.md mention it as a target. This is acceptable since CentOS 8 reached EOL, but a comment explaining the omission would help.


5. .github/workflows/build-nativeshims.yml - Assessment: Excellent

Strengths

  • Clean Zig integration: Downloads specific Zig version (0.13.0) and creates wrapper scripts
  • Correct target specification: Uses x86_64-linux-gnu.2.28 and aarch64-linux-gnu.2.28 targets
  • Consistent approach: Both AMD64 and ARM64 builds use identical Zig wrapper patterns
  • Good separation: Zig wrappers stored in $HOME/zig-wrappers and added to PATH via environment variables

Issues to Address

Minor Issue: Zig Version Hardcoded (lines 84, 134)

ZIG_VERSION="0.13.0"

Recommendation: Consider extracting this to a workflow input or env variable at the top level for easier updates:

env:
  ZIG_VERSION: "0.13.0"

Minor Enhancement: Add Validation Step

After building, run the test-glibc-compatibility.sh script automatically to verify the build succeeded:

- name: Verify glibc compatibility
  run: |
    cd Yubico.NativeShims
    chmod +x test-glibc-compatibility.sh
    ./test-glibc-compatibility.sh linux-x64/libYubico.NativeShims.so

6. cmake/aarch64-linux-gnu.toolchain.cmake - Assessment: Perfect

Strengths

  • Environment variable support: Correctly checks for $CC and $CXX environment variables first
  • Fallback to traditional toolchain: Gracefully falls back to aarch64-linux-gnu-gcc if environment variables aren't set
  • Clean and simple: Does exactly what's needed without over-complication

No issues found ✅

This is a well-designed toolchain file that properly supports both Zig wrappers and traditional cross-compilers.


Summary and Recommendations

Overall Assessment: EXCELLENT WORK

This PR demonstrates a sophisticated understanding of:

  • Cross-compilation challenges
  • glibc ABI compatibility
  • Symbol versioning
  • Comprehensive testing approaches
  • Professional documentation

The Zig-based approach is sound and aligns perfectly with Zig's design goals as described in the article you referenced (Zig as a powerful drop-in GCC/Clang replacement).

Critical Issues to Fix Before Merge

  1. TESTING.md: Update expected output to show glibc 2.25 (not 2.28) as the actual maximum version
  2. test-runtime-compatibility.sh: Add libpcsclite-dev to Dockerfile dependencies
  3. TEST-REPORT.md: Correct the date (shows 2025, should likely be 2024)

Recommended Enhancements

  1. Add glibc compatibility verification to CI workflow
  2. Extract Zig version to workflow-level environment variable
  3. Simplify version comparison logic in test-glibc-compatibility.sh
  4. Add comment explaining .NET installation approach in runtime test

Context: Zig as C Compiler Replacement

The approach in this PR leverages Zig's key strengths:

  • Hermetic cross-compilation: No need for system-specific toolchains
  • Precise glibc targeting: The -target <arch>-linux-gnu.2.28 flag acts as an ABI compatibility ceiling
  • Symbol version selection: Zig/LLVM automatically selects the oldest compatible symbol version for each function
  • Zero additional dependencies: Zig bundles libc headers and acts as both compiler and linker

This is exactly what Zig was designed for, and your implementation is textbook-correct.

Final Verdict

Status: Approve with minor fixes
Risk Level: Low
Compatibility Improvement: Excellent (4+ years of additional distribution support)


Tasks

  • Read and analyze all changed files
  • Review TEST-REPORT.md for soundness
  • Review TESTING.md for clarity and accuracy
  • Review test-glibc-compatibility.sh for correctness
  • Review build workflow changes
  • Review toolchain changes
  • Provide comprehensive feedback

| PR #336

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants