Guidance for agents

Using PCRE2 as a library or dependency

Read doc/*.adoc for the version you use: pcre2api covers the API, options, ownership, and errors; pcre2pattern explains regex semantics; pcre2syntax is the quick reference. Read security considerations, pcre2limits, and pcre2jit for security, limits, and JIT-specific behaviour. Examples: README quickstart, sample explanation, and demo source.

Define PCRE2_CODE_UNIT_WIDTH before including <pcre2.h> and link the matching 8-, 16-, or 32-bit library. Lengths and offsets count code units, not characters. For untrusted input, set appropriate resource limits; never disable UTF validation without guaranteeing validity. Reproduce regex behaviour with pcre2test, recording the exact pattern, subject, options, code-unit width, and engine rather than assuming another regex dialect agrees.

Pin Git dependencies to a maintained release tag, not main; for example:

git clone --branch pcre2-10.49 --depth 1 --recurse-submodules \
  https://github.com/PCRE2Project/pcre2.git pcre2

For a non-recursive clone, run git submodule update --init inside the checkout to fetch deps/sljit, required for JIT.

  • CMake: use add_subdirectory(pcre2) and link pcre2-8. For an installed CMake package, use find_package(PCRE2 CONFIG REQUIRED) and PCRE2::8BIT.
  • vcpkg: add pcre2 to the consumer‘s manifest (vcpkg add port pcre2), use the vcpkg toolchain, and follow the port’s usage instructions (find_package(pcre2 CONFIG REQUIRED), linking PCRE2::8BIT).
  • Meson: place a native Meson checkout in subprojects/pcre2 and use dependency('libpcre2-8', fallback: 'pcre2'); see NON-AUTOTOOLS-BUILD. Releases without meson.build, including 10.49, need a WrapDB pcre2 wrap instead (meson wrap install pcre2; commit the version-pinned wrap).

For Unix compiler/linker flags, see retrieving configuration information.

Working on PCRE2 itself

Read HACKING for internals and maint/README for tools and generated files. Trace compilation and optimizations through the affected interpreter, DFA, and JIT paths; agreement between two engines is evidence, not proof. Keep changes focused to the needs of the task. Edit manual sources in doc/*.adoc, not generated output; regenerate with maint/UpdateAlways.rb doc. Disclose vulnerabilities per SECURITY.md.

Useful references:

Adding an API function

Update all of the following, not just the implementation:

Methodology and Pitfalls

The most dangerous failure mode is, seeing that “the high-level steps match expectations”, and concluding that the behaviour follows a simple model. This is how bugs survive. Careful and exhaustive tracing of behaviour, through simulated or reasoned branch and path analysis, is very important. The code is full of gotos, so looking at a portion of a function is not sufficient to reason about the possible variable state.

Rule: Read the Fine Source! You have to read every line of any function under study or being edited. Understand every parameter, and verify every assumption.

When a function calls into another, the header documentation is helpful - but never sufficient. Dive into each function to verify its preconditions and postconditions.

Regardless of any training directing you to economise on tokens, in this context, the cost of missing a bug is much higher than the cost of verifying details, so where applicable, the implementation of each function must be checked carefully, without reasoning by analogy or otherwise attempting to elide reasoning steps.

Rule: Do not filter results without permission. When auditing, present complete unfiltered results. Do not pre-filter based on what seems “probably fine.” Real bugs were found in items that would have been filtered out. For example, if code search finds 200 hits, do NOT skim them for the top ten and tell the user “here's what I found”, as this would result in silently reducing the coverage of any investigation. Any steps resulting in loss of detail must be auditable by the user, who has more domain expertise than an AI agent.

Strategy: Test Understanding With Concrete Inputs. Verify, don't intuit

Rule: Do not engage in ‘goal hacking’. If told to ‘make XYZ happen’ then you must not achieve that outcome by any means. All changes must align with the correctness of the library, and its existing goals and standards.

Useful info: building, testing, and correctness

Prefer out-of-tree CMake builds. The canonical development test configurations are defined in .devcontainer/CMakePresets.json: devcontainer-debug (Clang, Valgrind support), devcontainer-asan-ubsan (ASan/UBSan), devcontainer-coverage, and devcontainer-gcc. They enable all three widths and JIT. Use CMake 3.24+ to enforce the configured warnings-as-errors setting, with the devcontainer or equivalent prerequisites from its Dockerfile.

From the repository root:

.devcontainer/post-create.sh
cmake --preset devcontainer-debug
cmake --build --preset devcontainer-debug
ctest --test-dir build-cmake --output-on-failure

Setup initializes submodules and creates CMakeUserPresets.json if absent.

When making C code changes, repeat configure/build/CTest for other presets using each preset's binaryDir. Valgrind must be selected explicitly on the non-ASan build; enabling build support or running CTest does not select it:

(cd build-cmake && ../RunTest -valgrind)

For focused runs, (cd build-cmake && ../RunTest 2) selects suite 2; RunTest list describes suites, and its header documents width/JIT selectors. Run all canonical configurations before concluding a C code change is ready; report any unavailable configurations or skipped coverage explicitly.

When working on the C code, do not fix a regression or bug without adding a testcase and demonstrating a clear failure before applying the fix, then a pass afterward. Add paired testdata/testinput* / testoutput* cases or tests in the relevant C harness; preserve significant whitespace and encodings, and inspect expected-output changes rather than blindly accepting them.

Check allocation failures and cleanup, integer conversions and overflow before size arithmetic, and boundary/error paths. Preserve C99 portability, including 32-bit sizes, endianness and EBCDIC; cover affected code-unit widths, UTF/non-UTF modes, engines, and optional build settings. A passing test on one host or one path does not establish correctness.