goblin: A Linter for GObject C Code
Over the past week, I’ve been building goblin, a linter specifically designed for GObject-based C codebases.
If you know Rust’s clippy or Go’s go vet, think of goblin as the same thing for GObject/GLib.
Why this exists
A large part of the Linux desktop stack (GTK, Mutter, Pango, NetworkManager) is built on GObject. These projects have evolved over decades and carry a lot of patterns that predate newer GLib helpers, are easy to misuse, or encode subtle lifecycle invariants that nothing verifies.
This leads to issues like missing dispose/finalize/constructed chain-ups (memory leaks or undefined behavior), incorrect property definitions, uninitialized GError* variables, or function declarations with no implementation.
These aren’t theoretical. This GTK merge request recently fixed several missing chain-ups in example code.
Despite this, the C ecosystem lacks a linter that understands GObject semantics. goblin exists to close that gap.
What goblin checks
goblin ships with 35 rules across different categories:
- Correctness: Real bugs like non-canonical property names, uninitialized
GError*, missingPROP_0 - Suspicious: Likely mistakes like missing implementations or redundant NULL checks
- Style: Idiomatic GLib usage (
g_strcmp0,g_str_equal()) - Complexity: Suggests modern helpers (
g_autoptr,g_clear_*,g_set_str()) - Performance: Optimizations like
G_PARAM_STATIC_STRINGSorg_object_notify_by_pspec() - Pedantic: Consistency checks (macro semicolons, matching declare/define pairs)
23 out of 35 rules are auto-fixable. You should apply fixes one rule at a time to review the changes:
goblin --fix --only use_g_strcmp0
goblin --fix --only use_clear_functions
CI/CD Integration
goblin fits into existing pipelines.
GitHub Actions
- name: Run goblin
run: goblin --format sarif > goblin.sarif
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: goblin.sarif
Results show up in the Security tab under "Code scanning" and inline on pull requests.
GitLab CI
goblin:
image: ghcr.io/bilelmoussaoui/goblin:latest
script:
- goblin --format sarif > goblin.sarif
artifacts:
reports:
sast: goblin.sarif
Results appear inline in merge requests.
Configuration
Rules default to warn, and can be tuned via goblin.toml:
min_glib_version = "2.40" # Auto-disable rules for newer versions
[rules]
g_param_spec_static_name_canonical = "error" # Make critical
use_g_strcmp0 = "warn" # Keep as warning
use_g_autoptr_inline_cleanup = "ignore" # Disable
# Per-rule ignore patterns
missing_implementation = { level = "error", ignore = ["src/backends/**"] }
You can adopt it gradually without fixing everything at once.
Try it
# Run via container
podman run --rm -v "$PWD:/workspace:Z" ghcr.io/bilelmoussaoui/goblin:latest
# Install locally
cargo install --git https://github.com/bilelmoussaoui/goblin goblin
# Usage
goblin # Lint current directory
goblin --fix # Apply automatic fixes
goblin --list-rules # Inspect available rules
The project is early, so feedback is especially valuable (false positives, missing checks, workflow issues, etc.).