~ober/jerboa-pcre2

Imported from ~/mine/jerboa-pcre2

download snapshot

about

# jerboa-pcre2

PCRE2 bindings for Jerboa.

Status: experimental. Treat this repository as a native FFI and hostile-input
regular expression component until the release gates in `SECURITY.md` and
`docs/ffi-boundary.md` are complete.

## Requirements

- Jerboa `jerbuild`
- C compiler
- `libpcre2-8` development headers and library
- `pkg-config` recommended

On Debian/Ubuntu:

```sh
sudo apt-get install build-essential pkg-config libpcre2-dev
```

## Build And Test

```sh
make test
make native-sanitizer-test
make hostile-regex-corpus
make audit
make pcre2-advisory-check
make reproducibility-report
make target-evidence
make release-evidence
```

`make test` builds `jerboa_pcre2_shim`, transpiles the Jerboa libraries, and
runs the PCRE2 regression, concurrent lifecycle, and native-loader policy
tests. If `jerbuild` is not installed, the Makefile bootstraps the pinned
Jerboa release into `.jerboa/bin`.

Dynamic development builds must explicitly set `JERBOA_PCRE2_DEV_NATIVE=1`
and set `JERBOA_PCRE2_LIB` to an absolute trusted directory containing
`jerboa_pcre2_shim.so` or `jerboa_pcre2_shim.dylib`. Relative paths, symlinked
directory components, unexpected owners, world-writable paths, disallowed
group-writable paths, current-directory lookup, and bare-name lookup are
rejected by the shared `(std native-loader)` policy. Explicit development mode
permits group-write only for components owned by the same unprivileged user.
Privileged processes ignore both development variables. Production builds
should statically link the shim;
statically linked hosts are detected from their registered PCRE2 shim symbol
and do not need either environment variable.

`make native-sanitizer-test` runs UBSan everywhere and ASan/TSan on Linux.
The current Apple sanitizer runtimes do not enter `main` reliably on this
macOS release, so Darwin builds compile those instrumented binaries and print
an explicit skip; Linux CI remains the required ASan/TSan execution gate.

`make hostile-regex-corpus` runs an expanded deterministic adversarial-pattern
corpus under low PCRE2 match/depth limits and records fail-closed behavior for
backtracking-heavy and quoted-literal shapes.

`make audit` records the PCRE2 version and native linkage for release notes.
`make release-evidence` writes the local release artifact bundle under
`dist/release-evidence/`, including toolchain identity, native linkage, a
minimal SBOM manifest, hostile-regex corpus output, PCRE2 advisory status,
source inputs, hashes, and a two-clean-build reproducibility report that also
compares repeated corpus output.

Production support is blocked until `make target-evidence` records a
marker-complete proof through `JPCRE2_TARGET_PROOF_FILE`; production release
hosts should set `JPCRE2_REQUIRE_TARGET_PROOF=1`. The proof covers target PCRE2
advisory/linkage review, platform CVE/backport review, hostile-regex soak,
downstream consumer integration, external regex/FFI review, and cross-platform
smoke. It must not contain private pattern corpora, secrets, private paths,
hostnames, or raw command output.

## Usage

```scheme
(import (jerboa-pcre2 pcre2))

(define rx (pcre2-compile "(?P<year>\\d{4})-(?P<month>\\d{2})"))
(define m (pcre2-search rx "Today is 2026-06"))

(pcre-match-group m 0)      ; => "2026-06"
(pcre-match-named m "year") ; => "2026"

(pcre2-release! rx)
```

PCRE2 is a backtracking engine. For untrusted patterns, set conservative match
limits with `(pcre2-set-match-limits! match-limit depth-limit)` and use an
admission/review step before running user-authored regular expressions.
Compiled regex objects may be shared between threads: match data and
substitution results are per operation, and `pcre2-release!` synchronizes with
in-flight native calls. New calls fail after release.

## API

| Function | Description |
| --- | --- |
| `(pcre2-compile pattern [options] [jit?])` | Compile a PCRE2 pattern |
| `(pcre2-regex pattern keyword: value ...)` | Compile with named options |
| `(pcre2-match rx subject [start])` | Full anchored match |
| `(pcre2-search rx subject [start])` | Unanchored search |
| `(pcre2-matches? rx subject [start])` | Boolean search |
| `(pcre-match-group m [n])` | Return group string or `#f` |
| `(pcre-match-named m name)` | Return named group |
| `(pcre-match-positions m [n])` | Return `(start . end)` |
| `(pcre2-replace rx subject replacement [start] [extended?])` | Replace first match |
| `(pcre2-replace-all rx subject replacement [start] [extended?])` | Replace all matches |
| `(pcre2-find-all rx subject [start])` | Return all match objects |
| `(pcre2-extract rx subject [start])` | Return matched strings |
| `(pcre2-fold rx kons knil subject [start])` | Fold over matches |
| `(pcre2-split rx subject [limit])` | Split by pattern |
| `(pcre2-partition rx subject)` | Alternating non-match/match list |
| `(pcre2-set-match-limits! match depth)` | Set per-thread PCRE2 match/depth limits |
| `(pcre2-quote str)` | Escape metacharacters |
| `(pcre2-release! rx)` | Free native resources |

Pregexp-compatible helpers are also provided:
`pcre2-pregexp-match`, `pcre2-pregexp-match-positions`,
`pcre2-pregexp-replace`, `pcre2-pregexp-replace*`, and
`pcre2-pregexp-quote`.

## Security

See `SECURITY.md`, `docs/ffi-boundary.md`,
`docs/pcre2-advisory-review.md`, and `docs/release-evidence.md`.

recent commits