From b3771dbc5f713ba3e90170c1dc3321e653222c65 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 2 Nov 2026 15:08:13 +1100 Subject: [PATCH] Construct C05 source roots and conditional header prefixes --- .../h25-c05-source-roots/DOMAIN-ARGUMENT.md | 29 + research/h25-c05-source-roots/OPEN-EDGES.json | 35 + research/h25-c05-source-roots/README.md | 30 + .../h25-c05-source-roots/SOURCE-PINS.json | 70 ++ research/h25-c05-source-roots/SOURCES.json | 18 + research/h25-c05-source-roots/TASK.json | 60 ++ research/h25-c05-source-roots/VALIDATION.json | 19 + research/h25-c05-source-roots/VERIFY.json | 34 + .../controls_source_roots_v1.py | 203 +++++ .../exec_failure/dict_probe_fields_v1.c.txt | 456 ++++++++++ .../field_loader_snapshot_v1.h.txt | 495 +++++++++++ .../exec_failure/field_service_v1.h.txt | 423 +++++++++ .../pyinit_failure/dict_probe_fields_v1.c.txt | 456 ++++++++++ .../field_loader_snapshot_v1.h.txt | 495 +++++++++++ .../pyinit_failure/field_service_v1.h.txt | 428 +++++++++ .../field-variant-producer-v2/CONDITIONS.json | 108 +++ .../variant_driver_v1.py.txt | 819 ++++++++++++++++++ .../integration/cold_build_evidence.py.txt | 312 +++++++ .../h25-c05-source-roots/source_roots_v1.py | 123 +++ 19 files changed, 4613 insertions(+) create mode 100644 research/h25-c05-source-roots/DOMAIN-ARGUMENT.md create mode 100644 research/h25-c05-source-roots/OPEN-EDGES.json create mode 100644 research/h25-c05-source-roots/README.md create mode 100644 research/h25-c05-source-roots/SOURCE-PINS.json create mode 100644 research/h25-c05-source-roots/SOURCES.json create mode 100644 research/h25-c05-source-roots/TASK.json create mode 100644 research/h25-c05-source-roots/VALIDATION.json create mode 100644 research/h25-c05-source-roots/VERIFY.json create mode 100644 research/h25-c05-source-roots/controls_source_roots_v1.py create mode 100644 research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/dict_probe_fields_v1.c.txt create mode 100644 research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/field_loader_snapshot_v1.h.txt create mode 100644 research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/field_service_v1.h.txt create mode 100644 research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/dict_probe_fields_v1.c.txt create mode 100644 research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/field_loader_snapshot_v1.h.txt create mode 100644 research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/field_service_v1.h.txt create mode 100644 research/h25-c05-source-roots/snapshot/areas/field-variant-producer-v2/CONDITIONS.json create mode 100644 research/h25-c05-source-roots/snapshot/areas/field-variant-producer-v2/variant_driver_v1.py.txt create mode 100644 research/h25-c05-source-roots/snapshot/stages/combined-finite-v8/integration/cold_build_evidence.py.txt create mode 100644 research/h25-c05-source-roots/source_roots_v1.py diff --git a/research/h25-c05-source-roots/DOMAIN-ARGUMENT.md b/research/h25-c05-source-roots/DOMAIN-ARGUMENT.md new file mode 100644 index 0000000000..b38fbacd45 --- /dev/null +++ b/research/h25-c05-source-roots/DOMAIN-ARGUMENT.md @@ -0,0 +1,29 @@ +# Source roots and the conditional prefix lemma + +This is a complete implementation of two limited pure functions. It is not a complete C05 inventory, genuine preparation observer, compiler model or original V03 control family. + +## Fixed-source root construction + +`source_roots` receives exactly six `(role, filename)` keys and exact bytes. It verifies each role-specific whole-source size/SHA256, emits six path occurrences with required installation mode0444, and constructs the unchanged list-valued GCC argv for each role. The known original sources contain20 literal include sites (ten per role). Whole-source binding plus independent enumeration of all literal directives establishes this fixed-source site list; the function is not a general C/preprocessor parser. Site serialization is deterministic C/loader/service order, not preprocessing event order. Identical payloads still retain distinct role/path occurrences. + +The returned `mode` is supplied binding data, not evidence of actual interpreter flags. Mode292 is the required installation permission, not an observation of local snapshot permissions. `CONFIGURATION`, `SOURCE_REVIEW` and `EXECUTION` remainNone selection markers; they are not an execution guard for these intentionally callable pure functions and do not activate any original gate. Returned records are data, not capabilities or an admission certificate. + +## Conditional ordinary-header prefix + +Let the supplied finite ordered effective chain be d1,...,dn, and name be the supported ordinary relative header name. Each candidate pair is `(di/name.gch, di/name)`. Under the stated no-PCH subcase, the constructor requires each reached .gch candidate to be MISSING, and records the preceding ordinary misses until the first REGULAR ordinary header. It returns that ordered prefix and its winner. + +Induction on the supplied chain proves the abstract first-match statement: every completed earlier pair has been recorded missing; the first regular ordinary candidate determines the returned result. Missing observations or unsupported outcomes leave the component open. Validation of all supplied facts and all chain paths precedes selection, including unused suffix paths. A later unused *lookup record* is not required once an earlier ordinary winner is reached. + +Agreement with the actual compiler is conditional on independently established effective-chain semantics, authentic/stable namespace facts, compatible cache state, and inactive remapping/custom header construction. The function establishes none of those premises. It conservatively rejects present PCHs, aliases, unsupported objects and read errors; those are open subcases, not proof that every legal original C05 configuration must be rejected. Root search directories, absolute includes and other unsupported forms remain outside this partial function's local domain. These local bounds do not redefine the original C05 domain or increase its caps. + +The [GCC13.4 PCH manual](https://gcc.gnu.org/onlinedocs/gcc-13.4.0/gcc/Precompiled-Headers.html) describes .gch consideration before ordinary headers and eligibility conditions. This is a mechanism reference, not proof of correspondence to the pinned Ubuntu compiler. The [preprocessor-options manual](https://gcc.gnu.org/onlinedocs/gcc-13.4.0/gcc/Preprocessor-Options.html) also explains why -M/-MM reports are not the unchanged original compilation: -M changes the processing mode, while -MM omits system headers. No such diagnostic was executed here. + +## Why this is partial C05 + +C05 requires independent complete project/system-header/include-search/macro/compiler/specs/linker/library witnesses. A fixed point F0=R(D,Gamma), F[n+1]=F[n] union E(F[n]) is complete only after root completeness, complete applicable edge expansion, authentic/current facts, termination with no unresolved edges, and actual projection/resource bounds are proved. The first-uncovered-input argument is conditional on those facts; an empty unresolved list cannot replace them. + +An absence is not a zero-byte regular file. A witness JSON hash authenticates bytes, not assertions of absence or effective search order. The pure tests explicitly retain a stale-facts counterexample: identical supplied observations can return the same certificate despite a changed latent namespace. An actual observer and its ownership/currentness proof remain missing. No fake Root, owner, syscall failure or native observation is used. + +The exact original helper body, SHA256aa0a315110e031e19291970c9611fe5e0f91465fa20eaec51e81186099563f78, is newly retained as inert input. The call-site audit observes no `env` or `cwd` keyword on its Popen call; that does not itself qualify the inherited caller context, module initialisation or runtime operation. Full C05 still needs the installed configured-rule edge, transitive original bytes, namespace authority evidence and selected parent limits. `OPEN-EDGES.json` preserves those obligations. + +All original APIs, commands, source selections, source_files meaning and caps remain unchanged. Original first-error/cleanup obligations remain due for any future acquiring observer. No new trust premise, generic accounting API, universal interpreter theorem, runtime qualification, complete cost fit, performance or selected-frontier result follows. diff --git a/research/h25-c05-source-roots/OPEN-EDGES.json b/research/h25-c05-source-roots/OPEN-EDGES.json new file mode 100644 index 0000000000..4fcd45b906 --- /dev/null +++ b/research/h25-c05-source-roots/OPEN-EDGES.json @@ -0,0 +1,35 @@ +{ + "schema": "h25-c05-source-open-edges-v1", + "full_c05": false, + "V03_family_complete": false, + "edges": [ + { + "id": "CONFIGURED_RULES", + "status": "OPEN", + "required": "Relevant installed GCC/cc1/assembler/linker/loader package/build configuration and source correspondence, including defaults, target hooks, specs/search and embedded scripts." + }, + { + "id": "HELPER_CONTEXT", + "status": "BODY_AVAILABLE_CALLER_CONTEXT_OPEN", + "required": "The exact aa0a3151... helper is now supplied; its Popen call has no env/cwd keyword. Bind actual inherited context and caller/pre-launch mutations before making runtime claims." + }, + { + "id": "NAMESPACE", + "status": "OPEN", + "required": "Genuine source-owned acquisition/capture/close observer for ordered positive/negative lookups and relevant alias/directory state, under justified original stability/ownership premises." + }, + { + "id": "EXPANSION", + "status": "OPEN", + "required": "Actual complete macro/include/include_next/PCH/specs/script/library/loader rule adapters and original bytes reached by them. Fixed project roots are not transitive closure." + }, + { + "id": "PARENT_LIMITS", + "status": "OPEN", + "required": "Exact selected epoch_schema_v5/group01_evidence sources and record/encoding/file bounds; complete inventory fit and complete costs remain unmeasured." + } + ], + "original_score": 43.5, + "original_activity_credit_added": 0, + "costs": "OPEN_NOT_ZERO" +} diff --git a/research/h25-c05-source-roots/README.md b/research/h25-c05-source-roots/README.md new file mode 100644 index 0000000000..69e1ade768 --- /dev/null +++ b/research/h25-c05-source-roots/README.md @@ -0,0 +1,30 @@ +# C05 pure source-root and conditional search-prefix prerequisite + +Implements the concrete pure enabling component returned by the completed C05 ChatGPT Pro consultation: exact six-source root/argv construction and a conditional ordinary-header no-PCH search-prefix constructor. Independent executable controls check actual source bytes, all20 literal include occurrences, exact original command syntax, invalid inputs, search-order/negative-lookup discriminators and the retained staleness boundary. + +The6365-byte implementation is preserved byte-for-byte at SHA256438cdc6c8b003d9a1b6a41889d6ac2f3d5bed25f77b430cf3b5f63c36c4e4612. Pro authored it and reports a separate agent review with repairs; Codex independently checked the source and ran its own controls. This is agent-assisted review, not human or proof-kernel acceptance. No prototype field, fact mapping or return value is a genuine capability or runtime admission. + +`DOMAIN-ARGUMENT.md` states the exact partial function domains, conditional first-match proof and unproved GCC/namespace premises. `OPEN-EDGES.json` keeps full C05/V03/observer/currentness/toolchain/parent-bound obligations open. Source-root serialization is not preprocessing event order; required0444 modes and supplied normal/optimized labels are not stat/flag observations. The selection markers remainNone, while the new pure functions are intentionally callable for isolated verification. + +## Reproduce + +```sh +python3 -B scripts/research_package.py --package research/h25-c05-source-roots --check-only +python3 -B scripts/research_package.py --package research/h25-c05-source-roots +``` + +Registered normal/-O controls execute **only the new pure component**, inspect inert original C/header bytes and parse original driver/helper AST. The archived Root/provider/producer/helper is never imported or executed; no compiler/native/original-control work or actual namespace observation occurs. All nine exact inert fixtures are inside this package for functional verification and cold availability; their original local history and complete executable closure are not asserted. SOURCE-PINS.json identifies the source packet at [PR6352](https://github.com/CrocSwap/integer-mult-bounds/pull/6352) and the additional exact original helper. The package has no unmerged external executable dependency. + +## Scope and lineage + +This accurately named enabling source unit is separate from the stopped V03 round. [PR6351](https://github.com/CrocSwap/integer-mult-bounds/pull/6351) and PR6352 publish the preceding source resolutions; PR6321/6029/5864 retain original lineage. PR6339's identity/ordinary-cleanup repair and PR6346/6347's separate custody/interpreter findings are not adopted or replayed here. Base7c49fe32c55de02c2c873655c804b16e4c3fef0a; source snapshots and original gates unchanged. + +## Open next questions + +Establish exact installed toolchain configuration/source correspondence and actual caller context, then construct complete rule adapters and a genuine stable namespace observer. Do not replace that work with a manually asserted complete inventory, raw witness hash, helper callback or category count. See TASK.json and OPEN-EDGES.json. + +Full original C05 and V03 remain incomplete. Original weighted43.5% (22/49), stage gates20%, overall milestones10%,24-component denominator and O03 status are unchanged. Original preparation/native execution remains unadmitted. All unmeasured physical/preparation/review/publication/final metadata costs remain OPEN_NOT_ZERO; no scientific budget, fit, gain or kappa claim. + +## Credit + +Chris R / Clear1nsight with substantial ChatGPT Pro source construction/agent review and OpenAI Codex independent source/controls/publication assistance. Retain original source/review authors, PR6321/6029/5864, unpaidmoon/Cursor Grok for PR6339 and Douglas R. Colkitt's circuit/network/native/verification lineage. Snapshots/notices unchanged; new source/controls/analysis Apache-2.0. diff --git a/research/h25-c05-source-roots/SOURCE-PINS.json b/research/h25-c05-source-roots/SOURCE-PINS.json new file mode 100644 index 0000000000..e837c15ad1 --- /dev/null +++ b/research/h25-c05-source-roots/SOURCE-PINS.json @@ -0,0 +1,70 @@ +{ + "schema": "h25-c05-source-roots-pins-v1", + "pure_component": { + "path": "source_roots_v1.py", + "bytes": 6365, + "sha256": "438cdc6c8b003d9a1b6a41889d6ac2f3d5bed25f77b430cf3b5f63c36c4e4612" + }, + "snapshots": [ + { + "path": "snapshot/areas/field-variant-producer-v2/variant_driver_v1.py.txt", + "origin": "areas/field-variant-producer-v2/variant_driver_v1.py", + "bytes": 41337, + "sha256": "cdb1479253358508088f8aa0e1e92e6c75ffcc127e54552698598a02de061254" + }, + { + "path": "snapshot/areas/field-variant-producer-v2/CONDITIONS.json", + "origin": "areas/field-variant-producer-v2/CONDITIONS.json", + "bytes": 6940, + "sha256": "70e237d6ee4ac2ccaadf01615e8106999718eb1fbb3cf7644c9fc6d3fd4463fe" + }, + { + "path": "snapshot/stages/combined-finite-v8/integration/cold_build_evidence.py.txt", + "origin": "stages/combined-finite-v8/integration/cold_build_evidence.py", + "bytes": 16463, + "sha256": "aa0a315110e031e19291970c9611fe5e0f91465fa20eaec51e81186099563f78" + }, + { + "path": "snapshot/areas/field-negative-variants-v1/pyinit_failure/dict_probe_fields_v1.c.txt", + "origin": "areas/field-negative-variants-v1/pyinit_failure/dict_probe_fields_v1.c", + "bytes": 17806, + "sha256": "e0188999d41a9ab26e8d3d5c37b18b2238b3af21b1db90895f01f7be76d50b65" + }, + { + "path": "snapshot/areas/field-negative-variants-v1/pyinit_failure/field_loader_snapshot_v1.h.txt", + "origin": "areas/field-negative-variants-v1/pyinit_failure/field_loader_snapshot_v1.h", + "bytes": 19495, + "sha256": "bf7ab049cea89c0a882b279e35b1383ac8f99b66aa4b9b8e1ca22eb9c24c5a8d" + }, + { + "path": "snapshot/areas/field-negative-variants-v1/pyinit_failure/field_service_v1.h.txt", + "origin": "areas/field-negative-variants-v1/pyinit_failure/field_service_v1.h", + "bytes": 17354, + "sha256": "7656cd37503986459c4133643372fec13d3e5ad5553881f0bf0343a9a3e11abd" + }, + { + "path": "snapshot/areas/field-negative-variants-v1/exec_failure/dict_probe_fields_v1.c.txt", + "origin": "areas/field-negative-variants-v1/exec_failure/dict_probe_fields_v1.c", + "bytes": 17806, + "sha256": "e0188999d41a9ab26e8d3d5c37b18b2238b3af21b1db90895f01f7be76d50b65" + }, + { + "path": "snapshot/areas/field-negative-variants-v1/exec_failure/field_loader_snapshot_v1.h.txt", + "origin": "areas/field-negative-variants-v1/exec_failure/field_loader_snapshot_v1.h", + "bytes": 19495, + "sha256": "bf7ab049cea89c0a882b279e35b1383ac8f99b66aa4b9b8e1ca22eb9c24c5a8d" + }, + { + "path": "snapshot/areas/field-negative-variants-v1/exec_failure/field_service_v1.h.txt", + "origin": "areas/field-negative-variants-v1/exec_failure/field_service_v1.h", + "bytes": 17040, + "sha256": "f5066831bd812e7e88fb971ba0e7ca86dbef91fc40a1a68c17b040ce474cd880" + } + ], + "availability": "Nine exact inert inputs retained for functional verification and cold availability; no original Git-history ancestry or executable/import-closure qualification asserted.", + "predecessor_source_packet": { + "PR": 6352, + "head": "b280be8dab15359159538e639b1d8c7deafc0612" + }, + "new_input": "Exact original cold_build_evidence.py was found locally at the required aa0a3151... pin after the completed Pro response. It is supplied here as inert source; it was not supplied to Pro during that turn." +} diff --git a/research/h25-c05-source-roots/SOURCES.json b/research/h25-c05-source-roots/SOURCES.json new file mode 100644 index 0000000000..594089b9c7 --- /dev/null +++ b/research/h25-c05-source-roots/SOURCES.json @@ -0,0 +1,18 @@ +{ + "schema_version": 1, + "base_commit": "7c49fe32c55de02c2c873655c804b16e4c3fef0a", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "d59b5035e7b4cbaa9d688a1d32dd0d6eb79c466a", + "sha256": "9b8d0eea95b3bf0dfcb7938a732a6439b87a2685dec2a5ab9e525b3b34debbfa" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "3404fbdd5e7529a0674eef26114b5071e4586cec", + "sha256": "ead6cdc9d0af6d58e8a49744d8ec8c7c15e13d2ba93c276c434bcf9b51b93a81" + } + ] +} diff --git a/research/h25-c05-source-roots/TASK.json b/research/h25-c05-source-roots/TASK.json new file mode 100644 index 0000000000..ef498dafbf --- /dev/null +++ b/research/h25-c05-source-roots/TASK.json @@ -0,0 +1,60 @@ +{ + "schema_version": 1, + "task_id": "portable-replay", + "priority_revision": 8, + "base_commit": "7c49fe32c55de02c2c873655c804b16e4c3fef0a", + "original_card": { + "id": "portable-replay", + "question": "Can one reproducible environment or artifact-comparison failure be repaired?", + "starting_points": [ + "research/gzip-container-reproducibility/README.md", + "docs/ci-verification.md" + ], + "methods": [ + "Reproduce one portability failure and add a minimal cross-environment fix.", + "Audit one canonical-payload comparison for omitted proof-relevant fields." + ], + "acceptance_gate": "Preserve immutable source hashes and proof-relevant content; a different compressed byte stream alone is not a mathematical mismatch.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_selected_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Resolve the current selected review, separate complex/ordinary BIT/admitted BIT/outer budgets, and compare the card against live handoffs before starting. Historical ceilings require exact source/model equivalence.", + "scope": "Source-binding orientation only; not a scientific replay or all-size proof. Materialize selected inputs if this checkout is sparse." + }, + "first_experiment": "Reproduce one specific mismatch or audit one canonical comparison for omitted proof-relevant fields.", + "bottleneck_link": "Portable exact checks prevent environment failures from blocking valid contributions.", + "allowed_variations": [ + "One interpreter/version mismatch or one payload field comparison." + ], + "scope_change_triggers": [ + "Removing immutable-source pins because generated compressed bytes differ." + ], + "overlap_terms": [ + "gzip container", + "reproducibility", + "canonical payload" + ] + }, + "scope_status": "changed", + "actual_scope": "Completed bounded C05 enabling component: exact six-source/20-literal-site roots and unchanged argv construction, plus a conditional ordinary-header no-PCH first-match prefix constructor. Full C05 domain, current namespace observer and original V03 family remain open.", + "scope_change_reason": "User authorised consulting Pro then implementing and publishing useful prerequisites, and explicitly publishing resolved questions. This is a new accurately named partial source component, not a resumed V03 round or full C05 acceptance.", + "bottleneck_link": "Source-bound verifier qualification prerequisites; no change to the multiplication supplier, selected result or framework assumptions.", + "budget_minutes": 60, + "stop_rule": "Stop on source mismatch or unresolved interpretation; no target/native/compiler/original-control execution, historical allowance transfer or silent scope change.", + "outcome": "partial", + "evidence": "source_roots_v1.py, independent pure controls, DOMAIN-ARGUMENT.md, exact inert inputs and explicit OPEN-EDGES.json.", + "author": "Chris R / Clear1nsight", + "ai_assistance": "ChatGPT Pro source consultation and substantial OpenAI Codex source-audit/verification assistance. These are agent-assisted findings, not human or proof-kernel acceptance.", + "open_questions": [ + { + "question": "Can configured compiler/helper/search/linker rules and genuine stable namespace evidence complete the original C05 domain?", + "why_it_matters": "Literal project include roots and a conditional prefix certificate do not account for all transitive/implicit inputs or authenticate supplied absence assertions.", + "first_step": "Bind exact installed toolchain build/configuration and original caller context; implement source-owned rule adapters and an actual observer with original custody and first-error guarantees.", + "blocked_by": "Installed-toolchain correspondence, effective search/macro/specs/linker rules, genuine namespace/alias currentness and parent record limits remain unqualified." + } + ] +} diff --git a/research/h25-c05-source-roots/VALIDATION.json b/research/h25-c05-source-roots/VALIDATION.json new file mode 100644 index 0000000000..53999a33a3 --- /dev/null +++ b/research/h25-c05-source-roots/VALIDATION.json @@ -0,0 +1,19 @@ +{ + "schema": "h25-c05-enabling-validation-v1", + "observed_utc": "2026-11-02T04:05:46.377577+00:00", + "python": "3.12.3", + "source_sha256": "438cdc6c8b003d9a1b6a41889d6ac2f3d5bed25f77b430cf3b5f63c36c4e4612", + "source_changed_from_Pro": false, + "metadata_and_pins": "PASS", + "registered_normal": "PASS_53_CONTROLS", + "registered_optimized": "PASS_53_CONTROLS", + "project_paths": 6, + "literal_sites": 20, + "stale_facts_counterexample": 1, + "original_archived_sources_executed": false, + "new_pure_component_executed": true, + "full_C05_or_V03_acceptance": false, + "original_activity_credit_added": 0, + "metadata_preparation_fix": "Required Open next questions heading added after checker refusal; implementation/fixtures/controls unchanged.", + "costs": "OPEN_NOT_ZERO" +} diff --git a/research/h25-c05-source-roots/VERIFY.json b/research/h25-c05-source-roots/VERIFY.json new file mode 100644 index 0000000000..010a785087 --- /dev/null +++ b/research/h25-c05-source-roots/VERIFY.json @@ -0,0 +1,34 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [], + "commands": [ + { + "argv": [ + "{python}", + "-I", + "-W", + "error", + "-B", + "{package}/controls_source_roots_v1.py" + ], + "timeout_seconds": 30, + "checks": "Execute only the new frozen pure component against exact inert payloads and labelled finite namespace data. Parse original driver/helper as AST, never import/run archived sources or native/compiler work. No full C05/V03 qualification." + }, + { + "argv": [ + "{python}", + "-I", + "-O", + "-W", + "error", + "-B", + "{package}/controls_source_roots_v1.py" + ], + "timeout_seconds": 30, + "checks": "Execute only the new frozen pure component against exact inert payloads and labelled finite namespace data. Parse original driver/helper as AST, never import/run archived sources or native/compiler work. No full C05/V03 qualification." + } + ] +} diff --git a/research/h25-c05-source-roots/controls_source_roots_v1.py b/research/h25-c05-source-roots/controls_source_roots_v1.py new file mode 100644 index 0000000000..a462e4e0d4 --- /dev/null +++ b/research/h25-c05-source-roots/controls_source_roots_v1.py @@ -0,0 +1,203 @@ +"""Independent pure controls. Archived sources are data and AST only.""" +from pathlib import Path +import ast +import copy +import hashlib +import json +import re +import types + +HERE = Path(__file__).resolve().parent +ROLES = ('pyinit_failure', 'exec_failure') +FILES = ('dict_probe_fields_v1.c', 'field_loader_snapshot_v1.h', 'field_service_v1.h') +CODE_SHA = '438cdc6c8b003d9a1b6a41889d6ac2f3d5bed25f77b430cf3b5f63c36c4e4612' +CHECKS = 0 + + +def need(value, message): + if value is not True: + raise RuntimeError(message) + + +def check(value, message): + global CHECKS + need(value, message) + CHECKS += 1 + + +def opened(impl, action, message): + try: + action() + except impl.ConstructionOpen: + check(True, message) + return + raise RuntimeError('unexpected acceptance: ' + message) + + +def snapshot_inputs(): + pins = json.loads((HERE / 'SOURCE-PINS.json').read_text()) + data = {} + for row in pins['snapshots']: + raw = (HERE / row['path']).read_bytes() + need(len(raw) == row['bytes'] and hashlib.sha256(raw).hexdigest() == row['sha256'], + 'inert source identity differs') + data[row['origin']] = raw + return data + + +def independent_sites(payloads, stage): + # This enumerates the known whole-source-pinned literal lines; it is not + # a general preprocessor or a claim about transitive/implicit includes. + result = [] + for role in ROLES: + for name in FILES: + path = stage + '/areas/field-negative-variants-v1/' + role + '/' + name + for number, line in enumerate(payloads[(role, name)].decode('ascii').splitlines(), 1): + if not line.lstrip().startswith('#include'): + continue + match = re.fullmatch(r'\s*#\s*include\s+([<"][^>"]+[>"])\s*', line) + need(match is not None, 'unexpected nonliteral directive in fixed source') + result.append((role, path, number, match.group(1))) + return tuple(result) + + +def independent_argv(driver_source, stage, output): + tree = ast.parse(driver_source) + main = next(n for n in tree.body if isinstance(n, ast.FunctionDef) and n.name == '_variant_main') + node = next(n.value for n in ast.walk(main) if isinstance(n, ast.Assign) and + any(isinstance(t, ast.Name) and t.id == 'command' for t in n.targets)) + need(isinstance(node, ast.List) and len(node.elts) == 13, 'original command shape differs') + prefix = [ast.literal_eval(n) for n in node.elts[:9]] + need(ast.unparse(node.elts[9]) == "'-I' + plan['include']" and + ast.unparse(node.elts[10]) == "row['source_path']" and + ast.literal_eval(node.elts[11]) == '-o' and ast.unparse(node.elts[12]) == 'target', + 'original command binding differs') + return tuple((role, prefix + ['-I/usr/include/python3.12', + stage + '/areas/field-negative-variants-v1/' + role + '/' + FILES[0], + '-o', output + '/' + role + '/_h25_dict_probe.cpython-312-x86_64-linux-gnu.so']) + for role in ROLES) + + +def main(): + data = snapshot_inputs() + raw = (HERE / 'source_roots_v1.py').read_bytes() + need(len(raw) == 6365 and hashlib.sha256(raw).hexdigest() == CODE_SHA, + 'frozen new pure source differs') + tree = ast.parse(raw) + need([ast.unparse(n) for n in tree.body if isinstance(n, (ast.Import, ast.ImportFrom))] == ['import hashlib'], + 'unexpected pure-component import') + # Only this new reviewed pure implementation executes. None of the + # original archived .txt/JSON/C/header inputs is compiled or executed. + impl = types.ModuleType('c05_pure_component') + exec(compile(raw, str(HERE / 'source_roots_v1.py'), 'exec', dont_inherit=True), impl.__dict__) + payloads = {(role, name): data['areas/field-negative-variants-v1/' + role + '/' + name] + for role in ROLES for name in FILES} + stage, output = '/owned-stage', '/owned-evidence' + expected_sites = independent_sites(payloads, stage) + check(len(expected_sites) == 20, 'twenty independently enumerated literal sites') + driver = data['areas/field-variant-producer-v2/variant_driver_v1.py'] + expected_argv = independent_argv(driver, stage, output) + original = copy.copy(payloads) + normal = impl.source_roots(payloads, stage, output, 'normal') + optimized = impl.source_roots(payloads, stage, output, 'optimized') + check(normal['literal_include_obligations'] == expected_sites, 'full fixed site list') + check(normal['commands'] == expected_argv and all(type(x[1]) is list for x in normal['commands']), + 'unchanged original list-valued argv') + check(normal['commands'] == optimized['commands'] and normal['mode'] != optimized['mode'], + 'supplied Python-mode binding preserves GCC flags') + expected_rows = [{'path': stage + '/areas/field-negative-variants-v1/' + role + '/' + name, + 'sha256': hashlib.sha256(payloads[(role, name)]).hexdigest(), + 'bytes': len(payloads[(role, name)]), 'mode': 0o444} + for role in ROLES for name in FILES] + check(normal['project_files'] == expected_rows and len(normal['project_files']) == 6, + 'six path occurrences retained; permissions are requirements') + check(normal['full_c05'] is False and normal['runtime_qualified'] is False, + 'no completeness or runtime authority') + check(payloads == original, 'constructor leaves input payload mapping unchanged') + check(sum(len(x) for x in payloads.values()) == 108996, 'project bytes') + for key in payloads: + bad = copy.copy(payloads) + bad[key] = bytes([bad[key][0] ^ 1]) + bad[key][1:] + opened(impl, lambda: impl.source_roots(bad, stage, output, 'normal'), 'each payload corruption') + bad = copy.copy(payloads) + a, b = (ROLES[0], FILES[2]), (ROLES[1], FILES[2]) + bad[a], bad[b] = bad[b], bad[a] + opened(impl, lambda: impl.source_roots(bad, stage, output, 'normal'), 'distinct service swap') + for name in FILES[:2]: + bad = copy.copy(payloads) + a, b = (ROLES[0], name), (ROLES[1], name) + bad[a], bad[b] = bad[b], bad[a] + check(impl.source_roots(bad, stage, output, 'normal') == normal, + 'equal-content swap positive') + for bad_mode in (False, 0, 'release'): + opened(impl, lambda: impl.source_roots(payloads, stage, output, bad_mode), 'invalid mode') + for bad_stage, bad_output in [('/bad/../stage', output), ('relative', output), + (stage, stage + '/nested'), (stage, stage), + (stage, '/bad//output'), (stage, '/')]: + opened(impl, lambda: impl.source_roots(payloads, bad_stage, bad_output, 'normal'), + 'path/domain refusal') + for bad in ({}, {**payloads, ('extra', 'key'): b''}, list(payloads.values())): + opened(impl, lambda: impl.source_roots(bad, stage, output, 'normal'), 'exact bounded payload domain') + + # Explicitly inert namespace DATA; these do not stand for a real Root, + # owner, syscall result, mount, compiler trace or admitted observer. + missing = ('MISSING', b'') + facts = {'/a/x.h.gch': missing, '/a/x.h': missing, + '/b/x.h.gch': missing, '/b/x.h': ('REGULAR', b'B')} + chain = ('/a', '/b') + result = impl.no_pch_prefix('x.h', chain, facts) + expected = (('/a/x.h.gch', 'MISSING'), ('/a/x.h', 'MISSING'), + ('/b/x.h.gch', 'MISSING'), + ('/b/x.h', 'REGULAR', hashlib.sha256(b'B').hexdigest(), 1)) + check(result == (expected, '/b/x.h'), 'conditional first-match prefix') + for key in ('/a/x.h.gch', '/a/x.h'): + bad = dict(facts) + del bad[key] + opened(impl, lambda: impl.no_pch_prefix('x.h', chain, bad), 'missing preceding observation') + early = {**facts, '/a/x.h': ('REGULAR', b'A')} + changed = impl.no_pch_prefix('x.h', chain, early) + check(changed[1] == '/a/x.h' and changed != result, 'earlier header changes winner') + reversed_result = impl.no_pch_prefix('x.h', tuple(reversed(chain)), facts) + check(reversed_result[1] == '/b/x.h' and reversed_result[0] != result[0], + 'search order changes ordered certificate') + prefix_only = {'/a/x.h.gch': missing, '/a/x.h': ('REGULAR', b'A')} + check(impl.no_pch_prefix('x.h', chain, prefix_only) == changed, + 'unused lookup suffix not necessary after first winner') + opened(impl, lambda: impl.no_pch_prefix('x.h', ('/a', '/bad/../suffix'), prefix_only), + 'unused chain paths still validated') + for disposition, raw_value in [('REGULAR', b'PCH'), ('DIRECTORY', b''), ('SYMLINK', b'alias'), ('ERROR', b'')]: + bad = dict(facts) + bad['/a/x.h.gch'] = (disposition, raw_value) + opened(impl, lambda: impl.no_pch_prefix('x.h', chain, bad), 'unsupported PCH/namespace subcase') + for bad_name in ('/absolute.h', '../x.h', 'x//y.h', 'x.h\x00'): + opened(impl, lambda: impl.no_pch_prefix(bad_name, chain, facts), 'unsupported include domain') + opened(impl, lambda: impl.no_pch_prefix('x.h', ['/a', '/b'], facts), 'exact tuple chain') + opened(impl, lambda: impl.no_pch_prefix('x.h', ('/a',) * 513, facts), 'chain bound') + bad = {**facts, '/unused': ('MISSING', b'invented absence bytes')} + opened(impl, lambda: impl.no_pch_prefix('x.h', chain, bad), 'absence is not a byte input') + bad = {**facts, '/unused': (True, b'')} + opened(impl, lambda: impl.no_pch_prefix('x.h', chain, bad), 'exact disposition type') + # Retain a limitation, not a fabricated stale-namespace rejection: this + # pure function cannot tell whether its supplied MISSING assertion is true. + latent_changed_namespace = early + check(impl.no_pch_prefix('x.h', chain, facts) == result and + impl.no_pch_prefix('x.h', chain, latent_changed_namespace) != result, + 'stale-data counterexample preserves external authenticity premise') + check(facts['/a/x.h'] == missing, 'prefix constructor leaves observations unchanged') + check(impl.CONFIGURATION is None and impl.SOURCE_REVIEW is None and impl.EXECUTION is None, + 'selection markers remain None') + + helper = ast.parse(data['stages/combined-finite-v8/integration/cold_build_evidence.py']) + launches = [n for n in ast.walk(helper) if isinstance(n, ast.Call) and + isinstance(n.func, ast.Attribute) and n.func.attr == 'Popen'] + check(len(launches) == 1 and not {'env', 'cwd'} & {kw.arg for kw in launches[0].keywords}, + 'original helper Popen has no explicit env/cwd keyword; caller remains open') + conditions = json.loads(data['areas/field-variant-producer-v2/CONDITIONS.json']) + check(any(row['id'] == 'C05' and 'Original dependency scan alone is insufficient.' in row['required'] + for row in conditions['conditions']), 'original C05 preserved') + print('PASS_C05_PURE_SOURCE_ROOTS controls=' + str(CHECKS) + + ' project_paths=6 literal_sites=20 stale_facts_counterexample=1 full_C05=false runtime_qualified=false') + + +if __name__ == '__main__': + main() diff --git a/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/dict_probe_fields_v1.c.txt b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/dict_probe_fields_v1.c.txt new file mode 100644 index 0000000000..e06cd4f4b0 --- /dev/null +++ b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/dict_probe_fields_v1.c.txt @@ -0,0 +1,456 @@ +/* Fresh dictionary collision-path metadata inspection. + * Source-derived from CPython 3.12.3 Objects/dictobject.c and private headers. + * See NOTICE-PSF.md and LICENSE-PSF.txt. No verdict or inspection result cache. + * SOURCE ONLY: parent compilation/execution gate is separate. + */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +#define Py_BUILD_CORE 1 +#define PY_SSIZE_T_CLEAN +#include +#include "internal/pycore_dict.h" +#include +#include +#include + +#if PY_VERSION_HEX != 0x030c03f0 +# error "This source admits only the authenticated CPython 3.12.3 header profile" +#endif +#if defined(Py_DEBUG) || defined(Py_TRACE_REFS) || defined(Py_GIL_DISABLED) +# error "Unsupported Python build profile" +#endif + +#define PROBE_SCHEMA 2 +#define PROBE_CAP 4096u +#define SHAPE_CAP 262144u +#define MAX_LOG2_SIZE 31u +#define PROBE_PERTURB_SHIFT 5u +_Static_assert(sizeof(void *) == 8, "pointer width"); +_Static_assert(sizeof(size_t) == 8, "size_t width"); +_Static_assert(sizeof(Py_ssize_t) == 8, "Py_ssize_t width"); +_Static_assert(sizeof(Py_hash_t) == 8, "hash width"); +_Static_assert(sizeof(long) == 8, "long width"); +_Static_assert(sizeof(PyDictObject) == 48, "dict object layout"); +_Static_assert(offsetof(PyDictObject, ma_keys) == 32, "dict keys offset"); +_Static_assert(offsetof(PyDictObject, ma_values) == 40, "dict values offset"); +_Static_assert(offsetof(PyDictKeysObject, dk_indices) == 32, "keys indices offset"); +_Static_assert(sizeof(PyDictKeyEntry) == 24, "general entry size"); +_Static_assert(DICT_MAX_WATCHERS == 8 && DICT_VERSION_MASK == 255, "watcher mask"); +_Static_assert(DKIX_EMPTY == -1 && DKIX_DUMMY == -2, "index sentinels"); + +typedef struct { + int armed; + int initialized; + int overflow; + int64_t interpreter_id; + hashfunc tuple_hash, long_hash, unicode_hash; + richcmpfunc tuple_compare, long_compare, unicode_compare; + destructor bool_dealloc; + PyMappingMethods *dict_mapping; + PySequenceMethods *dict_sequence; + binaryfunc dict_subscript; + objobjargproc dict_assign; + objobjproc dict_contains; + uint64_t calls, checks, safe, unsupported, empty_safe; + uint64_t slots, shape_items, hash_calls, matching_entries; + uint64_t bad_query, bad_layout, watched, bad_key, bad_value, budget; + uint64_t widths_seen; +} ProbeState; + +static void +add_count(ProbeState *state, uint64_t *counter, uint64_t amount) +{ + if (UINT64_MAX - *counter < amount) { + *counter = UINT64_MAX; + state->overflow = 1; + } + else { + *counter += amount; + } +} + +/* Public runtime/type metadata only; no dictionary private-field access. */ +static int +runtime_check(ProbeState *state) +{ + if (!state || !state->initialized || !PyGILState_Check() || + Py_Version != (unsigned long)PY_VERSION_HEX || + PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())) != state->interpreter_id || + state->interpreter_id != 0 || + PyDict_Type.tp_basicsize != (Py_ssize_t)sizeof(PyDictObject) || + PyTuple_Type.tp_basicsize != (Py_ssize_t)offsetof(PyTupleObject, ob_item) || + PyTuple_Type.tp_itemsize != (Py_ssize_t)sizeof(PyObject *) || + PyTuple_Type.tp_hash != state->tuple_hash || + PyLong_Type.tp_hash != state->long_hash || + PyUnicode_Type.tp_hash != state->unicode_hash || + PyTuple_Type.tp_richcompare != state->tuple_compare || + PyLong_Type.tp_richcompare != state->long_compare || + PyUnicode_Type.tp_richcompare != state->unicode_compare || + PyBool_Type.tp_dealloc != state->bool_dealloc || + PyDict_Type.tp_as_mapping != state->dict_mapping || + PyDict_Type.tp_as_sequence != state->dict_sequence || + !state->dict_mapping || !state->dict_sequence || + state->dict_mapping->mp_subscript != state->dict_subscript || + state->dict_mapping->mp_ass_subscript != state->dict_assign || + state->dict_sequence->sq_contains != state->dict_contains) { + PyErr_SetString(PyExc_RuntimeError, "Probe public runtime/type profile changed"); + return -1; + } + add_count(state, &state->checks, 1); + return 0; +} + +static ProbeState * +checked_state(PyObject *module, int require_armed) +{ + ProbeState *state = (ProbeState *)PyModule_GetState(module); + if (runtime_check(state) < 0) + return NULL; + if (require_armed && !state->armed) { + PyErr_SetString(PyExc_RuntimeError, "Probe is not authenticated and active"); + return NULL; + } + return state; +} + +static int +shape_item(ProbeState *state, uint32_t *used) +{ + if (*used >= SHAPE_CAP) + return 0; + ++*used; + add_count(state, &state->shape_items, 1); + return 1; +} + +/* Return 1 safe, 0 unsupported shape, -1 exhausted shape budget. + * Depth is exactly the original schema; no recursive user dispatch. */ +static int +integer_tuple_contents(ProbeState *state, PyObject *part, uint32_t *used) +{ + /* Caller has charged part before any type/size inspection. */ + if (!part || !PyTuple_CheckExact(part)) + return 0; + Py_ssize_t n = PyTuple_GET_SIZE(part); + for (Py_ssize_t i = 0; i < n; ++i) { + if (!shape_item(state, used)) + return -1; + PyObject *value = PyTuple_GET_ITEM(part, i); + if (!value || !PyLong_CheckExact(value)) + return 0; + } + return 1; +} + +static int +integer_tuple(ProbeState *state, PyObject *part, uint32_t *used) +{ + if (!shape_item(state, used)) + return -1; + return integer_tuple_contents(state, part, used); +} + +static int +key_shape(ProbeState *state, PyObject *key, uint32_t *used) +{ + if (!shape_item(state, used)) + return -1; + if (!key || !PyTuple_CheckExact(key) || PyTuple_GET_SIZE(key) != 2) + return 0; + PyObject *first = PyTuple_GET_ITEM(key, 0); + PyObject *second = PyTuple_GET_ITEM(key, 1); + if (!first || !second) + return 0; + if (!shape_item(state, used)) + return -1; /* charge first before its first type inspection */ + if (PyUnicode_CheckExact(first)) { + if (PyUnicode_GET_LENGTH(first) != 5 || + PyUnicode_READ_CHAR(first, 0) != 'l' || + PyUnicode_READ_CHAR(first, 1) != 'a' || + PyUnicode_READ_CHAR(first, 2) != 'b' || + PyUnicode_READ_CHAR(first, 3) != 'e' || + PyUnicode_READ_CHAR(first, 4) != 'l') + return 0; + } + else { + int first_ok = integer_tuple_contents(state, first, used); + if (first_ok != 1) + return first_ok; + } + return integer_tuple(state, second, used); +} + +/* Width and i were bounded before entry. memcpy avoids alignment/aliasing + * assumptions beyond the authenticated header's byte-array layout. */ +static Py_ssize_t +read_index_bytes(const char *indices, size_t i, unsigned int width) +{ + const char *address = indices + i * width; + if (width == 1) { + int8_t value; + memcpy(&value, address, sizeof value); + return value; + } + if (width == 2) { + int16_t value; + memcpy(&value, address, sizeof value); + return value; + } + int32_t value; + memcpy(&value, address, sizeof value); + return value; +} + +static PyObject * +unsupported(ProbeState *state, uint64_t *reason) +{ + add_count(state, &state->unsupported, 1); + add_count(state, reason, 1); + Py_RETURN_NOTIMPLEMENTED; +} + +static PyObject * +probe_inspect(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + ProbeState *state = checked_state(module, 1); + if (!state) + return NULL; + if (nargs != 2) { + PyErr_SetString(PyExc_TypeError, "inspect requires exactly mapping and key"); + return NULL; + } + add_count(state, &state->calls, 1); + PyObject *mapping = args[0], *query = args[1]; + if (!PyDict_CheckExact(mapping)) + return unsupported(state, &state->bad_layout); + uint32_t used = 0; + int query_ok = key_shape(state, query, &used); + if (query_ok != 1) + return unsupported(state, query_ok < 0 ? &state->budget : &state->bad_query); + add_count(state, &state->hash_calls, 1); + Py_hash_t hash = PyObject_Hash(query); + if (hash == -1) + return NULL; /* exact schema cannot normally fail; preserve exception */ + + /* First private ABI access: frontend must have authenticated and armed us. */ + PyDictObject *dict = (PyDictObject *)mapping; + if (dict->ma_values != NULL || dict->ma_keys == NULL || dict->ma_used < 0) + return unsupported(state, &state->bad_layout); + if ((dict->ma_version_tag & DICT_VERSION_MASK) != 0) + return unsupported(state, &state->watched); + PyDictKeysObject *keys = dict->ma_keys; + + /* Independently reviewed empty bootstrap: authenticated field profile, + * not pointer identity. No entry address or entry/value read occurs. */ + if (keys->dk_kind == DICT_KEYS_UNICODE && dict->ma_used == 0 && + keys->dk_log2_size == 0 && keys->dk_log2_index_bytes == 0 && + keys->dk_version == 1 && keys->dk_usable == 0 && + keys->dk_nentries == 0 && keys->dk_refcnt == _Py_IMMORTAL_REFCNT) { + int8_t first_index; + add_count(state, &state->slots, 1); + memcpy(&first_index, keys->dk_indices, sizeof first_index); + if (first_index != DKIX_EMPTY) + return unsupported(state, &state->bad_layout); + add_count(state, &state->empty_safe, 1); + add_count(state, &state->safe, 1); + Py_RETURN_TRUE; + } + if (keys->dk_kind != DICT_KEYS_GENERAL || keys->dk_refcnt != 1) + return unsupported(state, &state->bad_layout); + unsigned int log_size = keys->dk_log2_size; + if (log_size < 3 || log_size > MAX_LOG2_SIZE) + return unsupported(state, &state->bad_layout); + unsigned int width_log = log_size < 8 ? 0 : (log_size < 16 ? 1 : 2); + unsigned int width = 1u << width_log; + unsigned int index_log = log_size + width_log; + if (keys->dk_log2_index_bytes != index_log || index_log >= sizeof(size_t) * 8) + return unsupported(state, &state->bad_layout); + size_t table_size = (size_t)1 << log_size; + size_t entry_capacity = (table_size * 2) / 3; + if (keys->dk_nentries < 0 || keys->dk_usable < 0 || + (size_t)keys->dk_nentries > entry_capacity || + (size_t)keys->dk_usable > entry_capacity - (size_t)keys->dk_nentries || + dict->ma_used > keys->dk_nentries) + return unsupported(state, &state->bad_layout); + PyDictKeyEntry *entries = (PyDictKeyEntry *)(keys->dk_indices + ((size_t)1 << index_log)); + size_t mask = table_size - 1; + size_t perturb = (size_t)hash; + size_t index = (size_t)hash & mask; + state->widths_seen |= width; + for (uint32_t visits = 0; visits < PROBE_CAP; ++visits) { + add_count(state, &state->slots, 1); + Py_ssize_t slot = read_index_bytes(keys->dk_indices, index, width); + if (slot == DKIX_EMPTY) { + add_count(state, &state->safe, 1); + Py_RETURN_TRUE; + } + if (slot != DKIX_DUMMY) { + if (slot < 0 || slot >= keys->dk_nentries) + return unsupported(state, &state->bad_layout); + PyDictKeyEntry *entry = &entries[slot]; + if (entry->me_hash == hash) { + add_count(state, &state->matching_entries, 1); + int key_ok = key_shape(state, entry->me_key, &used); + if (key_ok != 1) + return unsupported(state, key_ok < 0 ? &state->budget : &state->bad_key); + /* TYPE ONLY: no truth/equality, reference retention or answer use. */ + if (entry->me_value == NULL || !Py_IS_TYPE(entry->me_value, &PyBool_Type)) + return unsupported(state, &state->bad_value); + } + } + perturb >>= PROBE_PERTURB_SHIFT; + index = (index * 5 + perturb + 1) & mask; + } + return unsupported(state, &state->budget); +} + +static PyObject * +probe_check(PyObject *module, PyObject *unused) +{ + (void)unused; + if (!checked_state(module, 1)) + return NULL; + Py_RETURN_NONE; +} + +static PyObject * +probe_activate(PyObject *module, PyObject *unused) +{ + (void)unused; + ProbeState *state = checked_state(module, 0); + if (!state) + return NULL; + if (state->armed) { + PyErr_SetString(PyExc_RuntimeError, "Probe module already has an owner"); + return NULL; + } + state->armed = 1; + Py_RETURN_NONE; +} + +static PyObject * +probe_deactivate(PyObject *module, PyObject *unused) +{ + (void)unused; + ProbeState *state = (ProbeState *)PyModule_GetState(module); + if (!state) { + PyErr_SetString(PyExc_RuntimeError, "Probe module state missing"); + return NULL; + } + state->armed = 0; + Py_RETURN_NONE; +} + +static PyObject * +probe_profile(PyObject *module, PyObject *unused) +{ + (void)unused; + if (!checked_state(module, 0)) + return NULL; + return Py_BuildValue("(iiiiiiiiiiiiiii)", PROBE_SCHEMA, PY_VERSION_HEX, + (int)sizeof(void *), (int)sizeof(size_t), (int)sizeof(Py_hash_t), + (int)sizeof(PyDictObject), (int)offsetof(PyDictObject, ma_keys), + (int)offsetof(PyDictObject, ma_values), + (int)offsetof(PyDictKeysObject, dk_indices), (int)sizeof(PyDictKeyEntry), + DICT_MAX_WATCHERS, PROBE_PERTURB_SHIFT, MAX_LOG2_SIZE, PROBE_CAP, SHAPE_CAP); +} + +static PyObject * +probe_counters(PyObject *module, PyObject *unused) +{ + (void)unused; + ProbeState *state = checked_state(module, 1); + if (!state) + return NULL; + return Py_BuildValue("{s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:i}", + "calls", (unsigned long long)state->calls, + "checks", (unsigned long long)state->checks, + "safe", (unsigned long long)state->safe, + "unsupported", (unsigned long long)state->unsupported, + "empty_safe", (unsigned long long)state->empty_safe, + "slots", (unsigned long long)state->slots, + "shape_items", (unsigned long long)state->shape_items, + "hash_calls", (unsigned long long)state->hash_calls, + "matching_entries", (unsigned long long)state->matching_entries, + "bad_query", (unsigned long long)state->bad_query, + "bad_layout", (unsigned long long)state->bad_layout, + "watched", (unsigned long long)state->watched, + "bad_key", (unsigned long long)state->bad_key, + "bad_value", (unsigned long long)state->bad_value, + "budget", (unsigned long long)state->budget, + "widths_seen", (unsigned long long)state->widths_seen, + "counter_overflow", state->overflow); +} + +static int +probe_exec(PyObject *module) +{ + ProbeState *state = (ProbeState *)PyModule_GetState(module); + if (!state) + return -1; + if (!PyGILState_Check() || Py_Version != (unsigned long)PY_VERSION_HEX || + PyDict_Type.tp_basicsize != (Py_ssize_t)sizeof(PyDictObject)) { + PyErr_SetString(PyExc_ImportError, "Probe unsupported public runtime profile"); + return -1; + } + state->interpreter_id = PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())); + state->tuple_hash = PyTuple_Type.tp_hash; + state->long_hash = PyLong_Type.tp_hash; + state->unicode_hash = PyUnicode_Type.tp_hash; + state->tuple_compare = PyTuple_Type.tp_richcompare; + state->long_compare = PyLong_Type.tp_richcompare; + state->unicode_compare = PyUnicode_Type.tp_richcompare; + state->bool_dealloc = PyBool_Type.tp_dealloc; + state->dict_mapping = PyDict_Type.tp_as_mapping; + state->dict_sequence = PyDict_Type.tp_as_sequence; + if (!state->dict_mapping || !state->dict_sequence || !state->tuple_hash || + !state->long_hash || !state->unicode_hash || !state->tuple_compare || + !state->long_compare || !state->unicode_compare || !state->bool_dealloc) { + PyErr_SetString(PyExc_ImportError, "Probe public type slots missing"); + return -1; + } + state->dict_subscript = state->dict_mapping->mp_subscript; + state->dict_assign = state->dict_mapping->mp_ass_subscript; + state->dict_contains = state->dict_sequence->sq_contains; + state->initialized = 1; + return runtime_check(state); +} + +/* Additive bootstrap helpers; their state and entries never enter field reads. */ +static struct PyModuleDef probe_module; +#include "field_loader_snapshot_v1.h" + +static PyMethodDef probe_methods[] = { + {"inspect", (PyCFunction)(void(*)(void))probe_inspect, METH_FASTCALL, "Fresh callback-safety metadata: True or NotImplemented."}, + {"check", probe_check, METH_NOARGS, "Check public runtime and captured type slots."}, + {"profile", probe_profile, METH_NOARGS, "Public build/profile metadata; no dict inspection."}, + {"counters", probe_counters, METH_NOARGS, "Fresh bounded operational counters; never authority."}, + {"_activate", probe_activate, METH_NOARGS, "Provider lifecycle after authenticated loading."}, + {"_deactivate", probe_deactivate, METH_NOARGS, "Release this module's active owner."}, + {"_field_loader_maps", probe_field_loader_maps, METH_NOARGS, "Once-only bootstrap map inventory; no symbol resolution."}, + {"_field_loader_snapshot", probe_field_loader_snapshot, METH_O, "Once-only admitted main-scope symbol resolution."}, + {NULL, NULL, 0, NULL} +}; +static PyModuleDef_Slot probe_slots[] = { + {Py_mod_exec, probe_exec}, + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + {0, NULL} +}; +static struct PyModuleDef probe_module = { + PyModuleDef_HEAD_INIT, + "_h25_dict_probe", + "Fresh source-bound dictionary probe metadata, without answer retention.", + sizeof(ProbeState), + probe_methods, + probe_slots, + NULL, NULL, NULL +}; +PyMODINIT_FUNC +PyInit__h25_dict_probe(void) +{ + return PyModuleDef_Init(&probe_module); +} + +/* Separate multiphase service, sharing no ProbeState or counters. */ +#include "field_service_v1.h" diff --git a/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/field_loader_snapshot_v1.h.txt b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/field_loader_snapshot_v1.h.txt new file mode 100644 index 0000000000..e59187ff62 --- /dev/null +++ b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/field_loader_snapshot_v1.h.txt @@ -0,0 +1,495 @@ +/* Bootstrap-only loader evidence, never used by field_id. + * This is not a loader or global-provider authentication replacement. Root + * authenticates these original builtin entries and the admitted process/OS + * closure before use. After maps(), Root must authenticate actual inventory, + * all requested definitions/winners/versions and every permitted OS IFUNC + * resolver/result family BEFORE snapshot() invokes dlsym/dlvsym. + * No named dlopen, dlclose, new namespace, or Python callback is introduced. + * Main handle is deliberately retained through process exit, including errors. + */ +#ifndef H25_FIELD_LOADER_SNAPSHOT_V1_H +#define H25_FIELD_LOADER_SNAPSHOT_V1_H + +#include +#include +#include + +#define H25_MAP_CAP 128 +#define H25_MAP_NAME_CAP 1024 +#define H25_PHDR_CAP 64 +#define H25_SEGMENT_CAP 32 +#define H25_SYMBOL_CAP 512 +#define H25_SYMBOL_NAME_CAP 256 +_Static_assert(RTLD_NOW == 2 && RTLD_LOCAL == 0 && LM_ID_BASE == 0, + "loader flag and base-namespace profile"); + +typedef struct { + uint64_t lo, hi; + unsigned int flags; +} H25LoadSegment; +typedef struct { + uint64_t base, phdr; + char name[H25_MAP_NAME_CAP]; + size_t segment_count; + H25LoadSegment segments[H25_SEGMENT_CAP]; +} H25MapRecord; +typedef struct { + size_t count; + unsigned long long adds, subs; + int failed; + H25MapRecord maps[H25_MAP_CAP]; +} H25MapSnapshot; +typedef struct { + const char *name, *version; + int weak, requested_type; + uint64_t address, provider_base; + const char *provider_name; + int has_address_symbol, address_symbol_type; + uint64_t address_symbol_address; +} H25SymbolResult; +_Static_assert(sizeof(H25LoadSegment) == 24, "loader segment storage profile"); +_Static_assert(sizeof(H25MapRecord) == 1816, "loader map storage profile"); +_Static_assert(sizeof(H25MapSnapshot) == 232480, "loader snapshot storage profile"); +_Static_assert(sizeof(H25SymbolResult) == 64, "loader symbol storage profile"); + +/* All storage is local to this ELF. There are no Python roots here. Static + * bounded buffers avoid unbounded loader callbacks or large C stack frames. + * Serialized bootstrap and no concurrent load mutation are inherited gates. */ +static H25MapSnapshot h25_loader_baseline, h25_loader_before, h25_loader_after; +static H25SymbolResult h25_loader_symbols[H25_SYMBOL_CAP]; +static void *h25_loader_main_handle; +static int h25_loader_maps_attempted, h25_loader_maps_ready; +static int h25_loader_symbols_attempted; + +static int +h25_loader_error(const char *message) +{ + PyErr_SetString(PyExc_RuntimeError, message); + return -1; +} + +static int +h25_loader_copy_name(char *to, const char *from) +{ + if (!from) + return -1; + for (size_t i = 0; i < H25_MAP_NAME_CAP; ++i) { + unsigned char c = (unsigned char)from[i]; + if (c > 127) + return -1; + to[i] = (char)c; + if (c == 0) + return 0; + } + return -1; +} + +/* Only called by authenticated libc dl_iterate_phdr, never by Python. */ +static int +h25_loader_collect(struct dl_phdr_info *info, size_t size, void *opaque) +{ + H25MapSnapshot *out = (H25MapSnapshot *)opaque; + if (size < offsetof(struct dl_phdr_info, dlpi_subs) + sizeof(info->dlpi_subs) || + out->count >= H25_MAP_CAP || !info->dlpi_phdr || + info->dlpi_phnum == 0 || info->dlpi_phnum > H25_PHDR_CAP) { + out->failed = 1; + return 1; + } + if (!out->count) { + out->adds = info->dlpi_adds; + out->subs = info->dlpi_subs; + } + else if (out->adds != info->dlpi_adds || out->subs != info->dlpi_subs) { + out->failed = 1; + return 1; + } + H25MapRecord *record = &out->maps[out->count]; + record->base = (uint64_t)info->dlpi_addr; + record->phdr = (uint64_t)(uintptr_t)info->dlpi_phdr; + record->segment_count = 0; + if (h25_loader_copy_name(record->name, info->dlpi_name) < 0) { + out->failed = 1; + return 1; + } + for (size_t i = 0; i < info->dlpi_phnum; ++i) { + const ElfW(Phdr) *p = &info->dlpi_phdr[i]; + if (p->p_type != PT_LOAD) + continue; + if (!p->p_memsz || p->p_filesz > p->p_memsz || + record->segment_count >= H25_SEGMENT_CAP || + p->p_vaddr > UINT64_MAX - record->base || + p->p_memsz > UINT64_MAX - (record->base + p->p_vaddr) || + (p->p_flags & ~(PF_R | PF_W | PF_X))) { + out->failed = 1; + return 1; + } + H25LoadSegment *segment = &record->segments[record->segment_count++]; + segment->lo = record->base + p->p_vaddr; + segment->hi = segment->lo + p->p_memsz; + segment->flags = p->p_flags; + } + if (!record->segment_count) { + out->failed = 1; + return 1; + } + ++out->count; + return 0; +} + +static int +h25_loader_take_maps(H25MapSnapshot *out) +{ + out->count = 0; + out->adds = out->subs = 0; + out->failed = 0; + int result = dl_iterate_phdr(h25_loader_collect, out); + if (result || out->failed || !out->count) + return h25_loader_error("Native loader map bounds/profile rejected"); + return 0; +} + +static int +h25_loader_same_maps(const H25MapSnapshot *a, const H25MapSnapshot *b) +{ + if (a->count != b->count || a->adds != b->adds || a->subs != b->subs) + return 0; + for (size_t i = 0; i < a->count; ++i) { + const H25MapRecord *x = &a->maps[i], *y = &b->maps[i]; + if (x->base != y->base || x->phdr != y->phdr || + x->segment_count != y->segment_count || strcmp(x->name, y->name)) + return 0; + for (size_t j = 0; j < x->segment_count; ++j) { + if (x->segments[j].lo != y->segments[j].lo || + x->segments[j].hi != y->segments[j].hi || + x->segments[j].flags != y->segments[j].flags) + return 0; + } + } + return 1; +} + +static int +h25_loader_module_check(PyObject *module) +{ + if (!PyModule_CheckExact(module) || PyModule_GetDef(module) != &probe_module) + return h25_loader_error("Loader helper requires original production owner"); + ProbeState *state = (ProbeState *)PyModule_GetState(module); + if (!state || !state->initialized || !state->armed || !PyGILState_Check() || + Py_Version != (unsigned long)PY_VERSION_HEX || state->interpreter_id != 0 || + PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())) != 0) + return h25_loader_error("Loader helper requires admitted active bootstrap"); + /* Original provider.guard already authenticated all original slots. Do not + * increment or repurpose the six original entries' metadata counters. */ + return 0; +} + +static int +h25_loader_namespace(void) +{ + Lmid_t namespace_id = (Lmid_t)-1; + struct link_map *main_map = NULL; + if (!h25_loader_main_handle || + dlinfo(h25_loader_main_handle, RTLD_DI_LMID, &namespace_id) != 0 || + namespace_id != LM_ID_BASE || + dlinfo(h25_loader_main_handle, RTLD_DI_LINKMAP, &main_map) != 0 || + !main_map || main_map->l_prev || !main_map->l_name || main_map->l_name[0]) + return h25_loader_error("Loader helper requires base main-program handle"); + if (!h25_loader_before.count || + h25_loader_before.maps[0].base != (uint64_t)main_map->l_addr || + h25_loader_before.maps[0].name[0]) + return h25_loader_error("Loader enumeration is not the admitted base namespace"); + return 0; +} + +static PyObject * +h25_loader_maps_tuple(const H25MapSnapshot *snapshot) +{ + PyObject *maps = PyTuple_New((Py_ssize_t)snapshot->count); + if (!maps) + return NULL; + for (size_t i = 0; i < snapshot->count; ++i) { + const H25MapRecord *record = &snapshot->maps[i]; + PyObject *segments = PyTuple_New((Py_ssize_t)record->segment_count); + if (!segments) { + Py_DECREF(maps); + return NULL; + } + for (size_t j = 0; j < record->segment_count; ++j) { + const H25LoadSegment *s = &record->segments[j]; + PyObject *segment = Py_BuildValue("(KKI)", + (unsigned long long)s->lo, (unsigned long long)s->hi, s->flags); + if (!segment) { + Py_DECREF(segments); + Py_DECREF(maps); + return NULL; + } + PyTuple_SET_ITEM(segments, (Py_ssize_t)j, segment); + } + PyObject *item = Py_BuildValue("(KKsO)", + (unsigned long long)record->base, (unsigned long long)record->phdr, + record->name, segments); + Py_DECREF(segments); + if (!item) { + Py_DECREF(maps); + return NULL; + } + PyTuple_SET_ITEM(maps, (Py_ssize_t)i, item); + } + return maps; +} + +static PyObject * +h25_loader_symbol_tuple(PyObject *requests, Py_ssize_t count) +{ + PyObject *results = PyTuple_New(count); + if (!results) + return NULL; + for (Py_ssize_t i = 0; i < count; ++i) { + H25SymbolResult *r = &h25_loader_symbols[i]; + PyObject *request = PyTuple_GET_ITEM(requests, i); + PyObject *provider = PyUnicode_FromString(r->provider_name ? r->provider_name : ""); + PyObject *address_type = r->has_address_symbol ? PyLong_FromLong(r->address_symbol_type) : Py_NewRef(Py_None); + PyObject *symbol_address = r->has_address_symbol ? PyLong_FromUnsignedLongLong(r->address_symbol_address) : Py_NewRef(Py_None); + if (!provider || !address_type || !symbol_address) { + Py_XDECREF(provider); Py_XDECREF(address_type); Py_XDECREF(symbol_address); + Py_DECREF(results); + return NULL; + } + PyObject *item = Py_BuildValue("(OOOOKKOOO)", + PyTuple_GET_ITEM(request, 0), PyTuple_GET_ITEM(request, 1), + PyTuple_GET_ITEM(request, 2), PyTuple_GET_ITEM(request, 3), + (unsigned long long)r->address, (unsigned long long)r->provider_base, + provider, address_type, symbol_address); + Py_DECREF(provider); Py_DECREF(address_type); Py_DECREF(symbol_address); + if (!item) { + Py_DECREF(results); + return NULL; + } + PyTuple_SET_ITEM(results, i, item); + } + return results; +} + +static PyObject * +h25_loader_result(PyObject *requests, Py_ssize_t count) +{ + PyObject *before = h25_loader_maps_tuple(&h25_loader_before); + if (!before) + return NULL; + PyObject *after = h25_loader_maps_tuple(&h25_loader_after); + if (!after) { + Py_DECREF(before); + return NULL; + } + PyObject *symbols = h25_loader_symbol_tuple(requests, count); + if (!symbols) { + Py_DECREF(before); Py_DECREF(after); + return NULL; + } + PyObject *result = Py_BuildValue("{s:s,s:i,s:i,s:s,s:O,s:O,s:O}", + "schema", "h25-native-provider-snapshot-v1", "namespace", 0, "flags", 2, + "scope", "retained-main-handle", "maps_before", before, "maps_after", after, + "symbol_results", symbols); + Py_DECREF(before); Py_DECREF(after); Py_DECREF(symbols); + return result; +} + +static PyObject * +probe_field_loader_maps(PyObject *module, PyObject *unused) +{ + (void)unused; + if (h25_loader_module_check(module) < 0) + return NULL; + if (h25_loader_maps_attempted) { + h25_loader_error("Loader map capture is single-use"); + return NULL; + } + h25_loader_maps_attempted = 1; + if (h25_loader_take_maps(&h25_loader_before) < 0) + return NULL; + /* glibc 2.39 dlfcn/dlopen.c selects BASE for NULL; dl-open.c names + * the main link map's searchlist as global scope. The existing main map + * is returned; no pathname/dependency load or scope promotion is asked. + * No dlclose occurs, even on error. Root must bill the retained handle. */ + h25_loader_main_handle = dlopen(NULL, RTLD_NOW | RTLD_LOCAL); + if (!h25_loader_main_handle) { + h25_loader_error("Retained main-program handle unavailable"); + return NULL; + } + if (h25_loader_namespace() < 0 || h25_loader_take_maps(&h25_loader_after) < 0) + return NULL; + if (!h25_loader_same_maps(&h25_loader_before, &h25_loader_after)) { + h25_loader_error("Main-program handle changed loaded maps"); + return NULL; + } + h25_loader_baseline = h25_loader_after; + PyObject *result = h25_loader_result(NULL, 0); + if (result) + h25_loader_maps_ready = 1; + return result; +} + +static int +h25_loader_ascii(PyObject *value, const char **out) +{ + if (!PyUnicode_CheckExact(value) || !PyUnicode_IS_ASCII(value) || + PyUnicode_GET_LENGTH(value) <= 0 || + PyUnicode_GET_LENGTH(value) >= H25_SYMBOL_NAME_CAP) + return h25_loader_error("Loader request name/version is not bounded exact ASCII"); + const char *data = (const char *)PyUnicode_1BYTE_DATA(value); + for (Py_ssize_t i = 0; i < PyUnicode_GET_LENGTH(value); ++i) { + if (!data[i]) + return h25_loader_error("Loader request name/version contains NUL"); + } + *out = data; + return 0; +} + +static int +h25_loader_requests(PyObject *requests, Py_ssize_t *count) +{ + if (!PyTuple_CheckExact(requests) || PyTuple_GET_SIZE(requests) > H25_SYMBOL_CAP) + return h25_loader_error("Loader requests require bounded exact tuple"); + *count = PyTuple_GET_SIZE(requests); + for (Py_ssize_t i = 0; i < *count; ++i) { + PyObject *request = PyTuple_GET_ITEM(requests, i); + if (!PyTuple_CheckExact(request) || PyTuple_GET_SIZE(request) != 4 || + !PyBool_Check(PyTuple_GET_ITEM(request, 2)) || + !PyLong_CheckExact(PyTuple_GET_ITEM(request, 3))) + return h25_loader_error("Loader request schema changed"); + H25SymbolResult *r = &h25_loader_symbols[i]; + r->name = r->version = r->provider_name = NULL; + r->address = r->provider_base = r->address_symbol_address = 0; + r->has_address_symbol = r->address_symbol_type = 0; + if (h25_loader_ascii(PyTuple_GET_ITEM(request, 0), &r->name) < 0) + return -1; + PyObject *version = PyTuple_GET_ITEM(request, 1); + if (version != Py_None && h25_loader_ascii(version, &r->version) < 0) + return -1; + r->weak = PyTuple_GET_ITEM(request, 2) == Py_True; + long symbol_type = PyLong_AsLong(PyTuple_GET_ITEM(request, 3)); + if (symbol_type == -1 && PyErr_Occurred()) + return -1; + if (symbol_type != STT_NOTYPE && symbol_type != STT_OBJECT && symbol_type != STT_FUNC) + return h25_loader_error("Loader request rejects unsupported import symbol kind"); + r->requested_type = (int)symbol_type; + for (Py_ssize_t j = 0; j < i; ++j) { + H25SymbolResult *previous = &h25_loader_symbols[j]; + if (!strcmp(r->name, previous->name) && + ((!r->version && !previous->version) || + (r->version && previous->version && !strcmp(r->version, previous->version)))) + return h25_loader_error("Loader requests contain duplicate symbol/version"); + } + } + return 0; +} + +static int +h25_loader_resolve(H25SymbolResult *result) +{ + (void)dlerror(); + /* Never RTLD_DEFAULT: that would use the ordinary caller DSO's local + * scope as well. The retained main handle searches the source-admitted + * base global scope. OS IFUNC authorization precedes this call in Root. */ + void *address = result->version ? + dlvsym(h25_loader_main_handle, result->name, result->version) : + dlsym(h25_loader_main_handle, result->name); + const char *error = dlerror(); + if (!address) { + if (!result->weak) + return h25_loader_error("Required strong global symbol did not resolve"); + if (!error) + return h25_loader_error("Resolved null symbol is outside unresolved-weak profile"); + /* Explicit unresolved weak zero. Root must match its admitted weak + * outcome. A strong symbol is never silently converted to weak zero. */ + return 0; + } + if (error) + return h25_loader_error("Loader symbol resolution returned inconsistent error"); + Dl_info info; + struct link_map *map = NULL; + if (!dladdr1(address, &info, (void **)&map, RTLD_DL_LINKMAP) || !map || !map->l_name) + return h25_loader_error("Resolved symbol has no admitted native provider map"); + size_t found = H25_MAP_CAP; + for (size_t i = 0; i < h25_loader_before.count; ++i) { + H25MapRecord *candidate = &h25_loader_before.maps[i]; + if (candidate->base == (uint64_t)map->l_addr && !strcmp(candidate->name, map->l_name)) { + if (found != H25_MAP_CAP) + return h25_loader_error("Resolved symbol provider map is ambiguous"); + found = i; + } + } + if (found == H25_MAP_CAP) + return h25_loader_error("Resolved symbol provider is absent from captured maps"); + H25MapRecord *provider = &h25_loader_before.maps[found]; + uint64_t location = (uint64_t)(uintptr_t)address; + int in_segment = 0; + for (size_t i = 0; i < provider->segment_count; ++i) { + if (location >= provider->segments[i].lo && location < provider->segments[i].hi) + in_segment = 1; + } + if (!in_segment) + return h25_loader_error("Resolved symbol is outside provider PT_LOAD ranges"); + result->address = location; + result->provider_base = provider->base; + result->provider_name = provider->name; + const ElfW(Sym) *address_symbol = NULL; + if (dladdr1(address, &info, (void **)&address_symbol, RTLD_DL_SYMENT) && + address_symbol && info.dli_saddr) { + result->has_address_symbol = 1; + result->address_symbol_type = ELF64_ST_TYPE(address_symbol->st_info); + result->address_symbol_address = (uint64_t)(uintptr_t)info.dli_saddr; + } + /* This last metadata describes only a nearest address symbol, potentially + * absent for hidden IFUNC implementation code. It is not a definition, + * resolver, binding or symbol-version assertion. */ + return 0; +} + +static void +h25_loader_forget_request_pointers(void) +{ + /* Request strings are borrowed only during the call, never retained. */ + for (size_t i = 0; i < H25_SYMBOL_CAP; ++i) { + h25_loader_symbols[i].name = NULL; + h25_loader_symbols[i].version = NULL; + h25_loader_symbols[i].provider_name = NULL; + } +} + +static PyObject * +probe_field_loader_snapshot(PyObject *module, PyObject *requests) +{ + if (h25_loader_module_check(module) < 0) + return NULL; + if (!h25_loader_maps_ready || h25_loader_symbols_attempted) { + h25_loader_error("Loader symbol capture requires successful maps and one attempt"); + return NULL; + } + h25_loader_symbols_attempted = 1; + Py_ssize_t count = 0; + PyObject *result = NULL; + if (h25_loader_requests(requests, &count) < 0 || + h25_loader_take_maps(&h25_loader_before) < 0 || h25_loader_namespace() < 0) + goto done; + if (!h25_loader_same_maps(&h25_loader_baseline, &h25_loader_before)) { + h25_loader_error("Loaded map history changed before symbol resolution"); + goto done; + } + for (Py_ssize_t i = 0; i < count; ++i) { + if (h25_loader_resolve(&h25_loader_symbols[i]) < 0) + goto done; + } + if (h25_loader_take_maps(&h25_loader_after) < 0) + goto done; + if (!h25_loader_same_maps(&h25_loader_before, &h25_loader_after)) { + h25_loader_error("Symbol resolution changed loaded maps"); + goto done; + } + result = h25_loader_result(requests, count); +done: + h25_loader_forget_request_pointers(); + return result; +} + +#endif diff --git a/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/field_service_v1.h.txt b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/field_service_v1.h.txt new file mode 100644 index 0000000000..787f997883 --- /dev/null +++ b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/exec_failure/field_service_v1.h.txt @@ -0,0 +1,423 @@ +/* Additive indexed field transport. SOURCE ONLY; no runtime admission. + * Original getter/id semantics: CPython 3.12.3 descrobject.c, funcobject.c, + * bltinmodule.c; attribution/license remain in the unchanged probe sources. + * No function-field structure access and no address-derived field IDs. + */ +#ifndef H25_FIELD_SERVICE_V1_H +#define H25_FIELD_SERVICE_V1_H + +#define H25_FIELD_MAGIC UINT64_C(0x4832354649454c44) +#define H25_FIELD_COUNT 7 +/* Concrete source-fixed pointer-table profile consumed by the separate ELF + * parser. These become compiler gates, not evidence of a current binary. */ +_Static_assert(sizeof(PyMethodDef) == 32, "field method table entry size"); +_Static_assert(sizeof(PyModuleDef) == 104, "field module definition size"); +_Static_assert(sizeof(PyModuleDef_Slot) == 16, "field module slot size"); +_Static_assert(offsetof(PyModuleDef, m_traverse) == 80, "module traverse offset"); +_Static_assert(offsetof(PyModuleDef, m_clear) == 88, "module clear offset"); +_Static_assert(offsetof(PyModuleDef, m_free) == 96, "module free offset"); +_Static_assert(offsetof(PyTypeObject, tp_dealloc) == 48, "context dealloc offset"); +_Static_assert(offsetof(PyTypeObject, tp_traverse) == 184, "context traverse offset"); +_Static_assert(offsetof(PyTypeObject, tp_clear) == 192, "context clear offset"); +enum { + H25_FIELD_UNBOUND = 0, H25_FIELD_BOUND = 1, H25_FIELD_CLOSING = 2, + H25_FIELD_CLOSED = 3, H25_FIELD_FAILED = 4 +}; + +typedef struct { + uint64_t magic; + int initialized, phase, bind_attempted, clear_pending, close_authorized; + int64_t interpreter_id; + Py_ssize_t active; + /* These are the only persistent Python roots. No targets or observations. */ + PyObject *getters[H25_FIELD_COUNT]; + PyObject *id0, *function_type, *close_token; +} H25FieldState; + +typedef struct { + PyObject_HEAD + H25FieldState state; +} H25FieldContext; +_Static_assert(sizeof(H25FieldState) == 128, "field primitive state size"); +_Static_assert(sizeof(H25FieldContext) == 144, "field fixture allocation size"); + +static struct PyModuleDef h25_field_module; +static PyTypeObject h25_field_context_type; +static unsigned int h25_field_context_created; +static int h25_field_exec_attempted; +#define H25_FIELD_CONTEXT_CAP 64u + +static H25FieldState * +h25_field_raw_state(PyObject *owner) +{ + if (Py_IS_TYPE(owner, &h25_field_context_type)) + return &((H25FieldContext *)owner)->state; + if (PyModule_CheckExact(owner) && PyModule_GetDef(owner) == &h25_field_module) + return (H25FieldState *)PyModule_GetState(owner); + return NULL; +} + +/* Clear each slot before decref. The token is an exact plain object, and the + * other roots are original builtin primitives, so cleanup adds no candidate + * finalizer. Keep token after logical close for authenticated idempotence. */ +static void +h25_field_drop_roots(H25FieldState *state, int drop_token) +{ + for (int i = 0; i < H25_FIELD_COUNT; ++i) + Py_CLEAR(state->getters[i]); + Py_CLEAR(state->id0); + Py_CLEAR(state->function_type); + if (drop_token) + Py_CLEAR(state->close_token); +} + +static H25FieldState * +h25_field_state(PyObject *module) +{ + H25FieldState *state = h25_field_raw_state(module); + if (!state) { + PyErr_SetString(PyExc_RuntimeError, "Field service owner changed"); + return NULL; + } + if (!state || !state->initialized || state->magic != H25_FIELD_MAGIC || + !PyGILState_Check() || Py_Version != (unsigned long)PY_VERSION_HEX || + state->interpreter_id != 0 || + PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())) != state->interpreter_id || + state->active < 0 || state->phase < H25_FIELD_UNBOUND || + state->phase > H25_FIELD_FAILED) { + PyErr_SetString(PyExc_RuntimeError, "Field service native state unavailable"); + return NULL; + } + return state; +} + +static PyObject * +h25_field_bind(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + H25FieldState *state = h25_field_state(module); + if (!state) + return NULL; + if (state->bind_attempted || state->phase != H25_FIELD_UNBOUND || + state->active || state->clear_pending) { + PyErr_SetString(PyExc_RuntimeError, "Field primitive binding is single-use"); + return NULL; + } + /* Failed first binding is terminal; there is no partial registration. */ + state->bind_attempted = 1; + state->phase = H25_FIELD_FAILED; + if (nargs != 4 || !PyTuple_CheckExact(args[0]) || + PyTuple_GET_SIZE(args[0]) != H25_FIELD_COUNT || + !PyCFunction_CheckExact(args[1]) || + PyCFunction_GET_FLAGS(args[1]) != METH_O || + args[2] != (PyObject *)&PyFunction_Type || + !Py_IS_TYPE(args[3], &PyBaseObject_Type)) { + PyErr_SetString(PyExc_TypeError, "Field binding requires exact original primitive packet"); + return NULL; + } + for (int i = 0; i < H25_FIELD_COUNT; ++i) { + if (!Py_IS_TYPE(PyTuple_GET_ITEM(args[0], i), &_PyMethodWrapper_Type)) { + PyErr_SetString(PyExc_TypeError, "Field getter must be an original bound method-wrapper"); + return NULL; + } + } + /* Root authenticates each object's identity and descriptor ownership before + * this call. The native type checks above are not substitute provenance. */ + for (int i = 0; i < H25_FIELD_COUNT; ++i) + state->getters[i] = Py_NewRef(PyTuple_GET_ITEM(args[0], i)); + state->id0 = Py_NewRef(args[1]); + state->function_type = Py_NewRef(args[2]); + state->close_token = Py_NewRef(args[3]); + state->phase = H25_FIELD_BOUND; + Py_RETURN_NONE; +} + +static void +h25_field_leave(H25FieldState *state) +{ + /* Each successful enter has exactly one leave, with the GIL continuously + * held apart from original getter/id callbacks' own behavior. */ + --state->active; + if (state->active == 0) { + if (state->clear_pending) { + state->phase = H25_FIELD_FAILED; + h25_field_drop_roots(state, 1); + } + else if (state->phase == H25_FIELD_CLOSING) { + state->phase = H25_FIELD_CLOSED; + h25_field_drop_roots(state, 0); + } + } +} + +static PyObject * +h25_field_id(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + H25FieldState *state = h25_field_state(module); + if (!state) + return NULL; + if (nargs != 2 || !PyFunction_Check(args[0]) || !PyLong_CheckExact(args[1])) { + PyErr_SetString(PyExc_TypeError, "field_id requires exact function and integer index"); + return NULL; + } + long index = PyLong_AsLong(args[1]); + if (index == -1 && PyErr_Occurred()) + return NULL; + if (index < 0 || index >= H25_FIELD_COUNT) { + PyErr_SetString(PyExc_IndexError, "field_id index must be in 0..6"); + return NULL; + } + if ((state->phase == H25_FIELD_CLOSING || state->phase == H25_FIELD_CLOSED) && + state->close_authorized && state->close_token && !state->clear_pending) { + /* Exact None can never be an original builtin id result. Root must + * independently witness legitimate CLOSING/CLOSED before fallback. */ + Py_RETURN_NONE; + } + if (state->phase != H25_FIELD_BOUND || state->clear_pending || + !state->bind_attempted || state->close_authorized || !state->close_token || + !state->getters[index] || !state->id0 || + state->function_type != (PyObject *)&PyFunction_Type) { + PyErr_SetString(PyExc_RuntimeError, "Field service is not bound and active"); + return NULL; + } + if (state->active == PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, "Field service active-call bound exhausted"); + return NULL; + } + /* Acquire every call root before the first observable field event. Neither + * a legitimate close nor GC clear may release state while active != 0. */ + PyObject *owner = Py_NewRef(module); + PyObject *getter = Py_NewRef(state->getters[index]); + PyObject *id0 = Py_NewRef(state->id0); + PyObject *function_type = Py_NewRef(state->function_type); + ++state->active; + PyObject *getter_args[2] = {args[0], function_type}; + PyObject *temporary = PyObject_Vectorcall(getter, getter_args, 2, NULL); + PyObject *result = NULL; + PyObject *error = NULL; + if (temporary) { + /* The original builtin id is invoked even after a legitimate close + * inside the getter. No direct field read, pointer-ID shortcut, retry + * or other field lookup occurs here. */ + result = PyObject_CallOneArg(id0, temporary); + if (!result) + error = PyErr_GetRaisedException(); + /* This is the original expression's temporary-release point. An id + * audit may have detached the field, making this its last reference. + * Its finalizer must run BEFORE return/Python's expected comparison. */ + Py_DECREF(temporary); + } + else { + error = PyErr_GetRaisedException(); + } + h25_field_leave(state); + Py_DECREF(function_type); + Py_DECREF(id0); + Py_DECREF(getter); + /* No state access after owner DECREF. */ + Py_DECREF(owner); + if (!result) + PyErr_SetRaisedException(error); + return result; +} + +static PyObject * +h25_field_close(PyObject *module, PyObject *token) +{ + H25FieldState *state = h25_field_state(module); + if (!state) + return NULL; + if (!state->close_token || token != state->close_token || state->clear_pending || + (state->phase != H25_FIELD_BOUND && state->phase != H25_FIELD_CLOSING && + state->phase != H25_FIELD_CLOSED)) { + PyErr_SetString(PyExc_RuntimeError, "Field close lacks the original owner token"); + return NULL; + } + state->close_authorized = 1; + state->phase = state->active ? H25_FIELD_CLOSING : H25_FIELD_CLOSED; + if (!state->active) + h25_field_drop_roots(state, 0); + Py_RETURN_NONE; +} + +static PyObject * +h25_field_status(PyObject *module, PyObject *unused) +{ + (void)unused; + H25FieldState *state = h25_field_state(module); + if (!state) + return NULL; + return Py_BuildValue("(iiniL)", 1, state->phase, state->active, + state->bind_attempted, (long long)state->interpreter_id); +} + +static PyObject * +h25_field_abi(PyObject *module, PyObject *unused) +{ + (void)unused; + if (!h25_field_state(module)) + return NULL; + return Py_BuildValue("(iiiii)", 1, H25_FIELD_COUNT, PY_VERSION_HEX, + (int)sizeof(void *), 2); +} + +static int +h25_field_traverse(PyObject *module, visitproc visit, void *arg) +{ + H25FieldState *state = h25_field_raw_state(module); + if (!state) + return 0; + for (int i = 0; i < H25_FIELD_COUNT; ++i) + Py_VISIT(state->getters[i]); + Py_VISIT(state->id0); + Py_VISIT(state->function_type); + Py_VISIT(state->close_token); + return 0; +} + +static int +h25_field_clear(PyObject *module) +{ + H25FieldState *state = h25_field_raw_state(module); + if (!state) + return 0; + state->clear_pending = 1; + state->phase = H25_FIELD_FAILED; + if (!state->active) + h25_field_drop_roots(state, 1); + return 0; +} + +static void +h25_field_free(void *module) +{ + /* An active call owns a strong module reference, so module deallocation + * cannot occur during that call. clear remains separately safe/deferred. */ + (void)h25_field_clear((PyObject *)module); + H25FieldState *state = h25_field_raw_state((PyObject *)module); + if (state) + state->magic = 0; +} + +static void +h25_field_context_dealloc(PyObject *context) +{ + /* An active field owns its context just as it owns the primary module. */ + PyObject_GC_UnTrack(context); + (void)h25_field_clear(context); + ((H25FieldContext *)context)->state.magic = 0; + PyObject_GC_Del(context); +} + +static PyObject * +h25_field_new_context(PyObject *module, PyObject *unused) +{ + (void)unused; + if (!PyModule_CheckExact(module) || PyModule_GetDef(module) != &h25_field_module || + !h25_field_state(module)) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "Field context factory requires original service module"); + return NULL; + } + if (h25_field_context_created >= H25_FIELD_CONTEXT_CAP) { + PyErr_SetString(PyExc_OverflowError, "Field fixture context bound exhausted"); + return NULL; + } + /* Count attempts, including allocation failure; no silent fixture retry. */ + ++h25_field_context_created; + H25FieldContext *context = PyObject_GC_New(H25FieldContext, &h25_field_context_type); + if (!context) + return NULL; + context->state = (H25FieldState){0}; + context->state.magic = H25_FIELD_MAGIC; + context->state.interpreter_id = 0; + context->state.initialized = 1; + context->state.phase = H25_FIELD_UNBOUND; + PyObject_GC_Track(context); + return (PyObject *)context; +} + +static int +h25_field_exec(PyObject *module) +{ + H25FieldState *state = (H25FieldState *)PyModule_GetState(module); + if (!state) + return -1; + if (h25_field_exec_attempted || state->initialized || !PyGILState_Check() || + Py_Version != (unsigned long)PY_VERSION_HEX) { + PyErr_SetString(PyExc_ImportError, "Field service initialization profile rejected"); + return -1; + } + h25_field_exec_attempted = 1; + int64_t interpreter_id = + PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())); + if (interpreter_id != 0) { + PyErr_SetString(PyExc_ImportError, "Field service requires the original main interpreter"); + return -1; + } + if (PyType_Ready(&h25_field_context_type) < 0) + return -1; + state->magic = H25_FIELD_MAGIC; + state->interpreter_id = interpreter_id; + state->initialized = 1; + state->phase = H25_FIELD_UNBOUND; + /* H25_NEGATIVE_FIXTURE_EXEC_V1: the original successful initialization + * prefix and every earlier error return remain unchanged. Only this + * separate paid fixture replaces the original success endpoint. + */ + PyErr_SetString(PyExc_RuntimeError, + "H25 negative exec fixture: deliberate failure after original initialization"); + return -1; +} + +static PyMethodDef h25_field_methods[] = { + {"field_id", (PyCFunction)(void(*)(void))h25_field_id, METH_FASTCALL, "One original getter/id event pair, with original temporary disposal."}, + {"_bind_fields", (PyCFunction)(void(*)(void))h25_field_bind, METH_FASTCALL, "Bind the authenticated original primitive packet exactly once."}, + {"_close_fields", h25_field_close, METH_O, "Logical close with original private token; active field completes once."}, + {"_field_status", h25_field_status, METH_NOARGS, "Native phase and active count; no target observations."}, + {"_field_abi", h25_field_abi, METH_NOARGS, "Immutable indexed-field interface profile."}, + {"_new_field_context", h25_field_new_context, METH_NOARGS, "Create one independently bound fixture context in this same image."}, + {NULL, NULL, 0, NULL} +}; +/* Separate table deliberately omits the factory: fixtures cannot manufacture + * other fixtures or reach mutable module storage. Methods remain native + * immutable PyCFunction objects strongly owning their actual context. */ +static PyMethodDef h25_field_context_methods[] = { + {"field_id", (PyCFunction)(void(*)(void))h25_field_id, METH_FASTCALL, "One original getter/id event pair, with original temporary disposal."}, + {"_bind_fields", (PyCFunction)(void(*)(void))h25_field_bind, METH_FASTCALL, "Bind the authenticated original primitive packet exactly once."}, + {"_close_fields", h25_field_close, METH_O, "Logical close with original private token; active field completes once."}, + {"_field_status", h25_field_status, METH_NOARGS, "Native phase and active count; no target observations."}, + {"_field_abi", h25_field_abi, METH_NOARGS, "Immutable indexed-field interface profile."}, + {NULL, NULL, 0, NULL} +}; +static PyTypeObject h25_field_context_type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "_h25_field_service_v1._FieldContext", + .tp_basicsize = sizeof(H25FieldContext), + .tp_dealloc = h25_field_context_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .tp_traverse = h25_field_traverse, + .tp_clear = h25_field_clear, + .tp_methods = h25_field_context_methods, + .tp_doc = "One-shot fixture primitive owner; no dictionary, target roots or reload." +}; +static PyModuleDef_Slot h25_field_slots[] = { + {Py_mod_exec, h25_field_exec}, + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + {0, NULL} +}; +static struct PyModuleDef h25_field_module = { + PyModuleDef_HEAD_INIT, + "_h25_field_service_v1", + "Source-bound indexed original-primitive transport without target retention.", + sizeof(H25FieldState), + h25_field_methods, + h25_field_slots, + h25_field_traverse, h25_field_clear, h25_field_free +}; +PyMODINIT_FUNC +PyInit__h25_field_service_v1(void) +{ + return PyModuleDef_Init(&h25_field_module); +} + +#endif diff --git a/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/dict_probe_fields_v1.c.txt b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/dict_probe_fields_v1.c.txt new file mode 100644 index 0000000000..e06cd4f4b0 --- /dev/null +++ b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/dict_probe_fields_v1.c.txt @@ -0,0 +1,456 @@ +/* Fresh dictionary collision-path metadata inspection. + * Source-derived from CPython 3.12.3 Objects/dictobject.c and private headers. + * See NOTICE-PSF.md and LICENSE-PSF.txt. No verdict or inspection result cache. + * SOURCE ONLY: parent compilation/execution gate is separate. + */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +#define Py_BUILD_CORE 1 +#define PY_SSIZE_T_CLEAN +#include +#include "internal/pycore_dict.h" +#include +#include +#include + +#if PY_VERSION_HEX != 0x030c03f0 +# error "This source admits only the authenticated CPython 3.12.3 header profile" +#endif +#if defined(Py_DEBUG) || defined(Py_TRACE_REFS) || defined(Py_GIL_DISABLED) +# error "Unsupported Python build profile" +#endif + +#define PROBE_SCHEMA 2 +#define PROBE_CAP 4096u +#define SHAPE_CAP 262144u +#define MAX_LOG2_SIZE 31u +#define PROBE_PERTURB_SHIFT 5u +_Static_assert(sizeof(void *) == 8, "pointer width"); +_Static_assert(sizeof(size_t) == 8, "size_t width"); +_Static_assert(sizeof(Py_ssize_t) == 8, "Py_ssize_t width"); +_Static_assert(sizeof(Py_hash_t) == 8, "hash width"); +_Static_assert(sizeof(long) == 8, "long width"); +_Static_assert(sizeof(PyDictObject) == 48, "dict object layout"); +_Static_assert(offsetof(PyDictObject, ma_keys) == 32, "dict keys offset"); +_Static_assert(offsetof(PyDictObject, ma_values) == 40, "dict values offset"); +_Static_assert(offsetof(PyDictKeysObject, dk_indices) == 32, "keys indices offset"); +_Static_assert(sizeof(PyDictKeyEntry) == 24, "general entry size"); +_Static_assert(DICT_MAX_WATCHERS == 8 && DICT_VERSION_MASK == 255, "watcher mask"); +_Static_assert(DKIX_EMPTY == -1 && DKIX_DUMMY == -2, "index sentinels"); + +typedef struct { + int armed; + int initialized; + int overflow; + int64_t interpreter_id; + hashfunc tuple_hash, long_hash, unicode_hash; + richcmpfunc tuple_compare, long_compare, unicode_compare; + destructor bool_dealloc; + PyMappingMethods *dict_mapping; + PySequenceMethods *dict_sequence; + binaryfunc dict_subscript; + objobjargproc dict_assign; + objobjproc dict_contains; + uint64_t calls, checks, safe, unsupported, empty_safe; + uint64_t slots, shape_items, hash_calls, matching_entries; + uint64_t bad_query, bad_layout, watched, bad_key, bad_value, budget; + uint64_t widths_seen; +} ProbeState; + +static void +add_count(ProbeState *state, uint64_t *counter, uint64_t amount) +{ + if (UINT64_MAX - *counter < amount) { + *counter = UINT64_MAX; + state->overflow = 1; + } + else { + *counter += amount; + } +} + +/* Public runtime/type metadata only; no dictionary private-field access. */ +static int +runtime_check(ProbeState *state) +{ + if (!state || !state->initialized || !PyGILState_Check() || + Py_Version != (unsigned long)PY_VERSION_HEX || + PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())) != state->interpreter_id || + state->interpreter_id != 0 || + PyDict_Type.tp_basicsize != (Py_ssize_t)sizeof(PyDictObject) || + PyTuple_Type.tp_basicsize != (Py_ssize_t)offsetof(PyTupleObject, ob_item) || + PyTuple_Type.tp_itemsize != (Py_ssize_t)sizeof(PyObject *) || + PyTuple_Type.tp_hash != state->tuple_hash || + PyLong_Type.tp_hash != state->long_hash || + PyUnicode_Type.tp_hash != state->unicode_hash || + PyTuple_Type.tp_richcompare != state->tuple_compare || + PyLong_Type.tp_richcompare != state->long_compare || + PyUnicode_Type.tp_richcompare != state->unicode_compare || + PyBool_Type.tp_dealloc != state->bool_dealloc || + PyDict_Type.tp_as_mapping != state->dict_mapping || + PyDict_Type.tp_as_sequence != state->dict_sequence || + !state->dict_mapping || !state->dict_sequence || + state->dict_mapping->mp_subscript != state->dict_subscript || + state->dict_mapping->mp_ass_subscript != state->dict_assign || + state->dict_sequence->sq_contains != state->dict_contains) { + PyErr_SetString(PyExc_RuntimeError, "Probe public runtime/type profile changed"); + return -1; + } + add_count(state, &state->checks, 1); + return 0; +} + +static ProbeState * +checked_state(PyObject *module, int require_armed) +{ + ProbeState *state = (ProbeState *)PyModule_GetState(module); + if (runtime_check(state) < 0) + return NULL; + if (require_armed && !state->armed) { + PyErr_SetString(PyExc_RuntimeError, "Probe is not authenticated and active"); + return NULL; + } + return state; +} + +static int +shape_item(ProbeState *state, uint32_t *used) +{ + if (*used >= SHAPE_CAP) + return 0; + ++*used; + add_count(state, &state->shape_items, 1); + return 1; +} + +/* Return 1 safe, 0 unsupported shape, -1 exhausted shape budget. + * Depth is exactly the original schema; no recursive user dispatch. */ +static int +integer_tuple_contents(ProbeState *state, PyObject *part, uint32_t *used) +{ + /* Caller has charged part before any type/size inspection. */ + if (!part || !PyTuple_CheckExact(part)) + return 0; + Py_ssize_t n = PyTuple_GET_SIZE(part); + for (Py_ssize_t i = 0; i < n; ++i) { + if (!shape_item(state, used)) + return -1; + PyObject *value = PyTuple_GET_ITEM(part, i); + if (!value || !PyLong_CheckExact(value)) + return 0; + } + return 1; +} + +static int +integer_tuple(ProbeState *state, PyObject *part, uint32_t *used) +{ + if (!shape_item(state, used)) + return -1; + return integer_tuple_contents(state, part, used); +} + +static int +key_shape(ProbeState *state, PyObject *key, uint32_t *used) +{ + if (!shape_item(state, used)) + return -1; + if (!key || !PyTuple_CheckExact(key) || PyTuple_GET_SIZE(key) != 2) + return 0; + PyObject *first = PyTuple_GET_ITEM(key, 0); + PyObject *second = PyTuple_GET_ITEM(key, 1); + if (!first || !second) + return 0; + if (!shape_item(state, used)) + return -1; /* charge first before its first type inspection */ + if (PyUnicode_CheckExact(first)) { + if (PyUnicode_GET_LENGTH(first) != 5 || + PyUnicode_READ_CHAR(first, 0) != 'l' || + PyUnicode_READ_CHAR(first, 1) != 'a' || + PyUnicode_READ_CHAR(first, 2) != 'b' || + PyUnicode_READ_CHAR(first, 3) != 'e' || + PyUnicode_READ_CHAR(first, 4) != 'l') + return 0; + } + else { + int first_ok = integer_tuple_contents(state, first, used); + if (first_ok != 1) + return first_ok; + } + return integer_tuple(state, second, used); +} + +/* Width and i were bounded before entry. memcpy avoids alignment/aliasing + * assumptions beyond the authenticated header's byte-array layout. */ +static Py_ssize_t +read_index_bytes(const char *indices, size_t i, unsigned int width) +{ + const char *address = indices + i * width; + if (width == 1) { + int8_t value; + memcpy(&value, address, sizeof value); + return value; + } + if (width == 2) { + int16_t value; + memcpy(&value, address, sizeof value); + return value; + } + int32_t value; + memcpy(&value, address, sizeof value); + return value; +} + +static PyObject * +unsupported(ProbeState *state, uint64_t *reason) +{ + add_count(state, &state->unsupported, 1); + add_count(state, reason, 1); + Py_RETURN_NOTIMPLEMENTED; +} + +static PyObject * +probe_inspect(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + ProbeState *state = checked_state(module, 1); + if (!state) + return NULL; + if (nargs != 2) { + PyErr_SetString(PyExc_TypeError, "inspect requires exactly mapping and key"); + return NULL; + } + add_count(state, &state->calls, 1); + PyObject *mapping = args[0], *query = args[1]; + if (!PyDict_CheckExact(mapping)) + return unsupported(state, &state->bad_layout); + uint32_t used = 0; + int query_ok = key_shape(state, query, &used); + if (query_ok != 1) + return unsupported(state, query_ok < 0 ? &state->budget : &state->bad_query); + add_count(state, &state->hash_calls, 1); + Py_hash_t hash = PyObject_Hash(query); + if (hash == -1) + return NULL; /* exact schema cannot normally fail; preserve exception */ + + /* First private ABI access: frontend must have authenticated and armed us. */ + PyDictObject *dict = (PyDictObject *)mapping; + if (dict->ma_values != NULL || dict->ma_keys == NULL || dict->ma_used < 0) + return unsupported(state, &state->bad_layout); + if ((dict->ma_version_tag & DICT_VERSION_MASK) != 0) + return unsupported(state, &state->watched); + PyDictKeysObject *keys = dict->ma_keys; + + /* Independently reviewed empty bootstrap: authenticated field profile, + * not pointer identity. No entry address or entry/value read occurs. */ + if (keys->dk_kind == DICT_KEYS_UNICODE && dict->ma_used == 0 && + keys->dk_log2_size == 0 && keys->dk_log2_index_bytes == 0 && + keys->dk_version == 1 && keys->dk_usable == 0 && + keys->dk_nentries == 0 && keys->dk_refcnt == _Py_IMMORTAL_REFCNT) { + int8_t first_index; + add_count(state, &state->slots, 1); + memcpy(&first_index, keys->dk_indices, sizeof first_index); + if (first_index != DKIX_EMPTY) + return unsupported(state, &state->bad_layout); + add_count(state, &state->empty_safe, 1); + add_count(state, &state->safe, 1); + Py_RETURN_TRUE; + } + if (keys->dk_kind != DICT_KEYS_GENERAL || keys->dk_refcnt != 1) + return unsupported(state, &state->bad_layout); + unsigned int log_size = keys->dk_log2_size; + if (log_size < 3 || log_size > MAX_LOG2_SIZE) + return unsupported(state, &state->bad_layout); + unsigned int width_log = log_size < 8 ? 0 : (log_size < 16 ? 1 : 2); + unsigned int width = 1u << width_log; + unsigned int index_log = log_size + width_log; + if (keys->dk_log2_index_bytes != index_log || index_log >= sizeof(size_t) * 8) + return unsupported(state, &state->bad_layout); + size_t table_size = (size_t)1 << log_size; + size_t entry_capacity = (table_size * 2) / 3; + if (keys->dk_nentries < 0 || keys->dk_usable < 0 || + (size_t)keys->dk_nentries > entry_capacity || + (size_t)keys->dk_usable > entry_capacity - (size_t)keys->dk_nentries || + dict->ma_used > keys->dk_nentries) + return unsupported(state, &state->bad_layout); + PyDictKeyEntry *entries = (PyDictKeyEntry *)(keys->dk_indices + ((size_t)1 << index_log)); + size_t mask = table_size - 1; + size_t perturb = (size_t)hash; + size_t index = (size_t)hash & mask; + state->widths_seen |= width; + for (uint32_t visits = 0; visits < PROBE_CAP; ++visits) { + add_count(state, &state->slots, 1); + Py_ssize_t slot = read_index_bytes(keys->dk_indices, index, width); + if (slot == DKIX_EMPTY) { + add_count(state, &state->safe, 1); + Py_RETURN_TRUE; + } + if (slot != DKIX_DUMMY) { + if (slot < 0 || slot >= keys->dk_nentries) + return unsupported(state, &state->bad_layout); + PyDictKeyEntry *entry = &entries[slot]; + if (entry->me_hash == hash) { + add_count(state, &state->matching_entries, 1); + int key_ok = key_shape(state, entry->me_key, &used); + if (key_ok != 1) + return unsupported(state, key_ok < 0 ? &state->budget : &state->bad_key); + /* TYPE ONLY: no truth/equality, reference retention or answer use. */ + if (entry->me_value == NULL || !Py_IS_TYPE(entry->me_value, &PyBool_Type)) + return unsupported(state, &state->bad_value); + } + } + perturb >>= PROBE_PERTURB_SHIFT; + index = (index * 5 + perturb + 1) & mask; + } + return unsupported(state, &state->budget); +} + +static PyObject * +probe_check(PyObject *module, PyObject *unused) +{ + (void)unused; + if (!checked_state(module, 1)) + return NULL; + Py_RETURN_NONE; +} + +static PyObject * +probe_activate(PyObject *module, PyObject *unused) +{ + (void)unused; + ProbeState *state = checked_state(module, 0); + if (!state) + return NULL; + if (state->armed) { + PyErr_SetString(PyExc_RuntimeError, "Probe module already has an owner"); + return NULL; + } + state->armed = 1; + Py_RETURN_NONE; +} + +static PyObject * +probe_deactivate(PyObject *module, PyObject *unused) +{ + (void)unused; + ProbeState *state = (ProbeState *)PyModule_GetState(module); + if (!state) { + PyErr_SetString(PyExc_RuntimeError, "Probe module state missing"); + return NULL; + } + state->armed = 0; + Py_RETURN_NONE; +} + +static PyObject * +probe_profile(PyObject *module, PyObject *unused) +{ + (void)unused; + if (!checked_state(module, 0)) + return NULL; + return Py_BuildValue("(iiiiiiiiiiiiiii)", PROBE_SCHEMA, PY_VERSION_HEX, + (int)sizeof(void *), (int)sizeof(size_t), (int)sizeof(Py_hash_t), + (int)sizeof(PyDictObject), (int)offsetof(PyDictObject, ma_keys), + (int)offsetof(PyDictObject, ma_values), + (int)offsetof(PyDictKeysObject, dk_indices), (int)sizeof(PyDictKeyEntry), + DICT_MAX_WATCHERS, PROBE_PERTURB_SHIFT, MAX_LOG2_SIZE, PROBE_CAP, SHAPE_CAP); +} + +static PyObject * +probe_counters(PyObject *module, PyObject *unused) +{ + (void)unused; + ProbeState *state = checked_state(module, 1); + if (!state) + return NULL; + return Py_BuildValue("{s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:K,s:i}", + "calls", (unsigned long long)state->calls, + "checks", (unsigned long long)state->checks, + "safe", (unsigned long long)state->safe, + "unsupported", (unsigned long long)state->unsupported, + "empty_safe", (unsigned long long)state->empty_safe, + "slots", (unsigned long long)state->slots, + "shape_items", (unsigned long long)state->shape_items, + "hash_calls", (unsigned long long)state->hash_calls, + "matching_entries", (unsigned long long)state->matching_entries, + "bad_query", (unsigned long long)state->bad_query, + "bad_layout", (unsigned long long)state->bad_layout, + "watched", (unsigned long long)state->watched, + "bad_key", (unsigned long long)state->bad_key, + "bad_value", (unsigned long long)state->bad_value, + "budget", (unsigned long long)state->budget, + "widths_seen", (unsigned long long)state->widths_seen, + "counter_overflow", state->overflow); +} + +static int +probe_exec(PyObject *module) +{ + ProbeState *state = (ProbeState *)PyModule_GetState(module); + if (!state) + return -1; + if (!PyGILState_Check() || Py_Version != (unsigned long)PY_VERSION_HEX || + PyDict_Type.tp_basicsize != (Py_ssize_t)sizeof(PyDictObject)) { + PyErr_SetString(PyExc_ImportError, "Probe unsupported public runtime profile"); + return -1; + } + state->interpreter_id = PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())); + state->tuple_hash = PyTuple_Type.tp_hash; + state->long_hash = PyLong_Type.tp_hash; + state->unicode_hash = PyUnicode_Type.tp_hash; + state->tuple_compare = PyTuple_Type.tp_richcompare; + state->long_compare = PyLong_Type.tp_richcompare; + state->unicode_compare = PyUnicode_Type.tp_richcompare; + state->bool_dealloc = PyBool_Type.tp_dealloc; + state->dict_mapping = PyDict_Type.tp_as_mapping; + state->dict_sequence = PyDict_Type.tp_as_sequence; + if (!state->dict_mapping || !state->dict_sequence || !state->tuple_hash || + !state->long_hash || !state->unicode_hash || !state->tuple_compare || + !state->long_compare || !state->unicode_compare || !state->bool_dealloc) { + PyErr_SetString(PyExc_ImportError, "Probe public type slots missing"); + return -1; + } + state->dict_subscript = state->dict_mapping->mp_subscript; + state->dict_assign = state->dict_mapping->mp_ass_subscript; + state->dict_contains = state->dict_sequence->sq_contains; + state->initialized = 1; + return runtime_check(state); +} + +/* Additive bootstrap helpers; their state and entries never enter field reads. */ +static struct PyModuleDef probe_module; +#include "field_loader_snapshot_v1.h" + +static PyMethodDef probe_methods[] = { + {"inspect", (PyCFunction)(void(*)(void))probe_inspect, METH_FASTCALL, "Fresh callback-safety metadata: True or NotImplemented."}, + {"check", probe_check, METH_NOARGS, "Check public runtime and captured type slots."}, + {"profile", probe_profile, METH_NOARGS, "Public build/profile metadata; no dict inspection."}, + {"counters", probe_counters, METH_NOARGS, "Fresh bounded operational counters; never authority."}, + {"_activate", probe_activate, METH_NOARGS, "Provider lifecycle after authenticated loading."}, + {"_deactivate", probe_deactivate, METH_NOARGS, "Release this module's active owner."}, + {"_field_loader_maps", probe_field_loader_maps, METH_NOARGS, "Once-only bootstrap map inventory; no symbol resolution."}, + {"_field_loader_snapshot", probe_field_loader_snapshot, METH_O, "Once-only admitted main-scope symbol resolution."}, + {NULL, NULL, 0, NULL} +}; +static PyModuleDef_Slot probe_slots[] = { + {Py_mod_exec, probe_exec}, + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + {0, NULL} +}; +static struct PyModuleDef probe_module = { + PyModuleDef_HEAD_INIT, + "_h25_dict_probe", + "Fresh source-bound dictionary probe metadata, without answer retention.", + sizeof(ProbeState), + probe_methods, + probe_slots, + NULL, NULL, NULL +}; +PyMODINIT_FUNC +PyInit__h25_dict_probe(void) +{ + return PyModuleDef_Init(&probe_module); +} + +/* Separate multiphase service, sharing no ProbeState or counters. */ +#include "field_service_v1.h" diff --git a/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/field_loader_snapshot_v1.h.txt b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/field_loader_snapshot_v1.h.txt new file mode 100644 index 0000000000..e59187ff62 --- /dev/null +++ b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/field_loader_snapshot_v1.h.txt @@ -0,0 +1,495 @@ +/* Bootstrap-only loader evidence, never used by field_id. + * This is not a loader or global-provider authentication replacement. Root + * authenticates these original builtin entries and the admitted process/OS + * closure before use. After maps(), Root must authenticate actual inventory, + * all requested definitions/winners/versions and every permitted OS IFUNC + * resolver/result family BEFORE snapshot() invokes dlsym/dlvsym. + * No named dlopen, dlclose, new namespace, or Python callback is introduced. + * Main handle is deliberately retained through process exit, including errors. + */ +#ifndef H25_FIELD_LOADER_SNAPSHOT_V1_H +#define H25_FIELD_LOADER_SNAPSHOT_V1_H + +#include +#include +#include + +#define H25_MAP_CAP 128 +#define H25_MAP_NAME_CAP 1024 +#define H25_PHDR_CAP 64 +#define H25_SEGMENT_CAP 32 +#define H25_SYMBOL_CAP 512 +#define H25_SYMBOL_NAME_CAP 256 +_Static_assert(RTLD_NOW == 2 && RTLD_LOCAL == 0 && LM_ID_BASE == 0, + "loader flag and base-namespace profile"); + +typedef struct { + uint64_t lo, hi; + unsigned int flags; +} H25LoadSegment; +typedef struct { + uint64_t base, phdr; + char name[H25_MAP_NAME_CAP]; + size_t segment_count; + H25LoadSegment segments[H25_SEGMENT_CAP]; +} H25MapRecord; +typedef struct { + size_t count; + unsigned long long adds, subs; + int failed; + H25MapRecord maps[H25_MAP_CAP]; +} H25MapSnapshot; +typedef struct { + const char *name, *version; + int weak, requested_type; + uint64_t address, provider_base; + const char *provider_name; + int has_address_symbol, address_symbol_type; + uint64_t address_symbol_address; +} H25SymbolResult; +_Static_assert(sizeof(H25LoadSegment) == 24, "loader segment storage profile"); +_Static_assert(sizeof(H25MapRecord) == 1816, "loader map storage profile"); +_Static_assert(sizeof(H25MapSnapshot) == 232480, "loader snapshot storage profile"); +_Static_assert(sizeof(H25SymbolResult) == 64, "loader symbol storage profile"); + +/* All storage is local to this ELF. There are no Python roots here. Static + * bounded buffers avoid unbounded loader callbacks or large C stack frames. + * Serialized bootstrap and no concurrent load mutation are inherited gates. */ +static H25MapSnapshot h25_loader_baseline, h25_loader_before, h25_loader_after; +static H25SymbolResult h25_loader_symbols[H25_SYMBOL_CAP]; +static void *h25_loader_main_handle; +static int h25_loader_maps_attempted, h25_loader_maps_ready; +static int h25_loader_symbols_attempted; + +static int +h25_loader_error(const char *message) +{ + PyErr_SetString(PyExc_RuntimeError, message); + return -1; +} + +static int +h25_loader_copy_name(char *to, const char *from) +{ + if (!from) + return -1; + for (size_t i = 0; i < H25_MAP_NAME_CAP; ++i) { + unsigned char c = (unsigned char)from[i]; + if (c > 127) + return -1; + to[i] = (char)c; + if (c == 0) + return 0; + } + return -1; +} + +/* Only called by authenticated libc dl_iterate_phdr, never by Python. */ +static int +h25_loader_collect(struct dl_phdr_info *info, size_t size, void *opaque) +{ + H25MapSnapshot *out = (H25MapSnapshot *)opaque; + if (size < offsetof(struct dl_phdr_info, dlpi_subs) + sizeof(info->dlpi_subs) || + out->count >= H25_MAP_CAP || !info->dlpi_phdr || + info->dlpi_phnum == 0 || info->dlpi_phnum > H25_PHDR_CAP) { + out->failed = 1; + return 1; + } + if (!out->count) { + out->adds = info->dlpi_adds; + out->subs = info->dlpi_subs; + } + else if (out->adds != info->dlpi_adds || out->subs != info->dlpi_subs) { + out->failed = 1; + return 1; + } + H25MapRecord *record = &out->maps[out->count]; + record->base = (uint64_t)info->dlpi_addr; + record->phdr = (uint64_t)(uintptr_t)info->dlpi_phdr; + record->segment_count = 0; + if (h25_loader_copy_name(record->name, info->dlpi_name) < 0) { + out->failed = 1; + return 1; + } + for (size_t i = 0; i < info->dlpi_phnum; ++i) { + const ElfW(Phdr) *p = &info->dlpi_phdr[i]; + if (p->p_type != PT_LOAD) + continue; + if (!p->p_memsz || p->p_filesz > p->p_memsz || + record->segment_count >= H25_SEGMENT_CAP || + p->p_vaddr > UINT64_MAX - record->base || + p->p_memsz > UINT64_MAX - (record->base + p->p_vaddr) || + (p->p_flags & ~(PF_R | PF_W | PF_X))) { + out->failed = 1; + return 1; + } + H25LoadSegment *segment = &record->segments[record->segment_count++]; + segment->lo = record->base + p->p_vaddr; + segment->hi = segment->lo + p->p_memsz; + segment->flags = p->p_flags; + } + if (!record->segment_count) { + out->failed = 1; + return 1; + } + ++out->count; + return 0; +} + +static int +h25_loader_take_maps(H25MapSnapshot *out) +{ + out->count = 0; + out->adds = out->subs = 0; + out->failed = 0; + int result = dl_iterate_phdr(h25_loader_collect, out); + if (result || out->failed || !out->count) + return h25_loader_error("Native loader map bounds/profile rejected"); + return 0; +} + +static int +h25_loader_same_maps(const H25MapSnapshot *a, const H25MapSnapshot *b) +{ + if (a->count != b->count || a->adds != b->adds || a->subs != b->subs) + return 0; + for (size_t i = 0; i < a->count; ++i) { + const H25MapRecord *x = &a->maps[i], *y = &b->maps[i]; + if (x->base != y->base || x->phdr != y->phdr || + x->segment_count != y->segment_count || strcmp(x->name, y->name)) + return 0; + for (size_t j = 0; j < x->segment_count; ++j) { + if (x->segments[j].lo != y->segments[j].lo || + x->segments[j].hi != y->segments[j].hi || + x->segments[j].flags != y->segments[j].flags) + return 0; + } + } + return 1; +} + +static int +h25_loader_module_check(PyObject *module) +{ + if (!PyModule_CheckExact(module) || PyModule_GetDef(module) != &probe_module) + return h25_loader_error("Loader helper requires original production owner"); + ProbeState *state = (ProbeState *)PyModule_GetState(module); + if (!state || !state->initialized || !state->armed || !PyGILState_Check() || + Py_Version != (unsigned long)PY_VERSION_HEX || state->interpreter_id != 0 || + PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())) != 0) + return h25_loader_error("Loader helper requires admitted active bootstrap"); + /* Original provider.guard already authenticated all original slots. Do not + * increment or repurpose the six original entries' metadata counters. */ + return 0; +} + +static int +h25_loader_namespace(void) +{ + Lmid_t namespace_id = (Lmid_t)-1; + struct link_map *main_map = NULL; + if (!h25_loader_main_handle || + dlinfo(h25_loader_main_handle, RTLD_DI_LMID, &namespace_id) != 0 || + namespace_id != LM_ID_BASE || + dlinfo(h25_loader_main_handle, RTLD_DI_LINKMAP, &main_map) != 0 || + !main_map || main_map->l_prev || !main_map->l_name || main_map->l_name[0]) + return h25_loader_error("Loader helper requires base main-program handle"); + if (!h25_loader_before.count || + h25_loader_before.maps[0].base != (uint64_t)main_map->l_addr || + h25_loader_before.maps[0].name[0]) + return h25_loader_error("Loader enumeration is not the admitted base namespace"); + return 0; +} + +static PyObject * +h25_loader_maps_tuple(const H25MapSnapshot *snapshot) +{ + PyObject *maps = PyTuple_New((Py_ssize_t)snapshot->count); + if (!maps) + return NULL; + for (size_t i = 0; i < snapshot->count; ++i) { + const H25MapRecord *record = &snapshot->maps[i]; + PyObject *segments = PyTuple_New((Py_ssize_t)record->segment_count); + if (!segments) { + Py_DECREF(maps); + return NULL; + } + for (size_t j = 0; j < record->segment_count; ++j) { + const H25LoadSegment *s = &record->segments[j]; + PyObject *segment = Py_BuildValue("(KKI)", + (unsigned long long)s->lo, (unsigned long long)s->hi, s->flags); + if (!segment) { + Py_DECREF(segments); + Py_DECREF(maps); + return NULL; + } + PyTuple_SET_ITEM(segments, (Py_ssize_t)j, segment); + } + PyObject *item = Py_BuildValue("(KKsO)", + (unsigned long long)record->base, (unsigned long long)record->phdr, + record->name, segments); + Py_DECREF(segments); + if (!item) { + Py_DECREF(maps); + return NULL; + } + PyTuple_SET_ITEM(maps, (Py_ssize_t)i, item); + } + return maps; +} + +static PyObject * +h25_loader_symbol_tuple(PyObject *requests, Py_ssize_t count) +{ + PyObject *results = PyTuple_New(count); + if (!results) + return NULL; + for (Py_ssize_t i = 0; i < count; ++i) { + H25SymbolResult *r = &h25_loader_symbols[i]; + PyObject *request = PyTuple_GET_ITEM(requests, i); + PyObject *provider = PyUnicode_FromString(r->provider_name ? r->provider_name : ""); + PyObject *address_type = r->has_address_symbol ? PyLong_FromLong(r->address_symbol_type) : Py_NewRef(Py_None); + PyObject *symbol_address = r->has_address_symbol ? PyLong_FromUnsignedLongLong(r->address_symbol_address) : Py_NewRef(Py_None); + if (!provider || !address_type || !symbol_address) { + Py_XDECREF(provider); Py_XDECREF(address_type); Py_XDECREF(symbol_address); + Py_DECREF(results); + return NULL; + } + PyObject *item = Py_BuildValue("(OOOOKKOOO)", + PyTuple_GET_ITEM(request, 0), PyTuple_GET_ITEM(request, 1), + PyTuple_GET_ITEM(request, 2), PyTuple_GET_ITEM(request, 3), + (unsigned long long)r->address, (unsigned long long)r->provider_base, + provider, address_type, symbol_address); + Py_DECREF(provider); Py_DECREF(address_type); Py_DECREF(symbol_address); + if (!item) { + Py_DECREF(results); + return NULL; + } + PyTuple_SET_ITEM(results, i, item); + } + return results; +} + +static PyObject * +h25_loader_result(PyObject *requests, Py_ssize_t count) +{ + PyObject *before = h25_loader_maps_tuple(&h25_loader_before); + if (!before) + return NULL; + PyObject *after = h25_loader_maps_tuple(&h25_loader_after); + if (!after) { + Py_DECREF(before); + return NULL; + } + PyObject *symbols = h25_loader_symbol_tuple(requests, count); + if (!symbols) { + Py_DECREF(before); Py_DECREF(after); + return NULL; + } + PyObject *result = Py_BuildValue("{s:s,s:i,s:i,s:s,s:O,s:O,s:O}", + "schema", "h25-native-provider-snapshot-v1", "namespace", 0, "flags", 2, + "scope", "retained-main-handle", "maps_before", before, "maps_after", after, + "symbol_results", symbols); + Py_DECREF(before); Py_DECREF(after); Py_DECREF(symbols); + return result; +} + +static PyObject * +probe_field_loader_maps(PyObject *module, PyObject *unused) +{ + (void)unused; + if (h25_loader_module_check(module) < 0) + return NULL; + if (h25_loader_maps_attempted) { + h25_loader_error("Loader map capture is single-use"); + return NULL; + } + h25_loader_maps_attempted = 1; + if (h25_loader_take_maps(&h25_loader_before) < 0) + return NULL; + /* glibc 2.39 dlfcn/dlopen.c selects BASE for NULL; dl-open.c names + * the main link map's searchlist as global scope. The existing main map + * is returned; no pathname/dependency load or scope promotion is asked. + * No dlclose occurs, even on error. Root must bill the retained handle. */ + h25_loader_main_handle = dlopen(NULL, RTLD_NOW | RTLD_LOCAL); + if (!h25_loader_main_handle) { + h25_loader_error("Retained main-program handle unavailable"); + return NULL; + } + if (h25_loader_namespace() < 0 || h25_loader_take_maps(&h25_loader_after) < 0) + return NULL; + if (!h25_loader_same_maps(&h25_loader_before, &h25_loader_after)) { + h25_loader_error("Main-program handle changed loaded maps"); + return NULL; + } + h25_loader_baseline = h25_loader_after; + PyObject *result = h25_loader_result(NULL, 0); + if (result) + h25_loader_maps_ready = 1; + return result; +} + +static int +h25_loader_ascii(PyObject *value, const char **out) +{ + if (!PyUnicode_CheckExact(value) || !PyUnicode_IS_ASCII(value) || + PyUnicode_GET_LENGTH(value) <= 0 || + PyUnicode_GET_LENGTH(value) >= H25_SYMBOL_NAME_CAP) + return h25_loader_error("Loader request name/version is not bounded exact ASCII"); + const char *data = (const char *)PyUnicode_1BYTE_DATA(value); + for (Py_ssize_t i = 0; i < PyUnicode_GET_LENGTH(value); ++i) { + if (!data[i]) + return h25_loader_error("Loader request name/version contains NUL"); + } + *out = data; + return 0; +} + +static int +h25_loader_requests(PyObject *requests, Py_ssize_t *count) +{ + if (!PyTuple_CheckExact(requests) || PyTuple_GET_SIZE(requests) > H25_SYMBOL_CAP) + return h25_loader_error("Loader requests require bounded exact tuple"); + *count = PyTuple_GET_SIZE(requests); + for (Py_ssize_t i = 0; i < *count; ++i) { + PyObject *request = PyTuple_GET_ITEM(requests, i); + if (!PyTuple_CheckExact(request) || PyTuple_GET_SIZE(request) != 4 || + !PyBool_Check(PyTuple_GET_ITEM(request, 2)) || + !PyLong_CheckExact(PyTuple_GET_ITEM(request, 3))) + return h25_loader_error("Loader request schema changed"); + H25SymbolResult *r = &h25_loader_symbols[i]; + r->name = r->version = r->provider_name = NULL; + r->address = r->provider_base = r->address_symbol_address = 0; + r->has_address_symbol = r->address_symbol_type = 0; + if (h25_loader_ascii(PyTuple_GET_ITEM(request, 0), &r->name) < 0) + return -1; + PyObject *version = PyTuple_GET_ITEM(request, 1); + if (version != Py_None && h25_loader_ascii(version, &r->version) < 0) + return -1; + r->weak = PyTuple_GET_ITEM(request, 2) == Py_True; + long symbol_type = PyLong_AsLong(PyTuple_GET_ITEM(request, 3)); + if (symbol_type == -1 && PyErr_Occurred()) + return -1; + if (symbol_type != STT_NOTYPE && symbol_type != STT_OBJECT && symbol_type != STT_FUNC) + return h25_loader_error("Loader request rejects unsupported import symbol kind"); + r->requested_type = (int)symbol_type; + for (Py_ssize_t j = 0; j < i; ++j) { + H25SymbolResult *previous = &h25_loader_symbols[j]; + if (!strcmp(r->name, previous->name) && + ((!r->version && !previous->version) || + (r->version && previous->version && !strcmp(r->version, previous->version)))) + return h25_loader_error("Loader requests contain duplicate symbol/version"); + } + } + return 0; +} + +static int +h25_loader_resolve(H25SymbolResult *result) +{ + (void)dlerror(); + /* Never RTLD_DEFAULT: that would use the ordinary caller DSO's local + * scope as well. The retained main handle searches the source-admitted + * base global scope. OS IFUNC authorization precedes this call in Root. */ + void *address = result->version ? + dlvsym(h25_loader_main_handle, result->name, result->version) : + dlsym(h25_loader_main_handle, result->name); + const char *error = dlerror(); + if (!address) { + if (!result->weak) + return h25_loader_error("Required strong global symbol did not resolve"); + if (!error) + return h25_loader_error("Resolved null symbol is outside unresolved-weak profile"); + /* Explicit unresolved weak zero. Root must match its admitted weak + * outcome. A strong symbol is never silently converted to weak zero. */ + return 0; + } + if (error) + return h25_loader_error("Loader symbol resolution returned inconsistent error"); + Dl_info info; + struct link_map *map = NULL; + if (!dladdr1(address, &info, (void **)&map, RTLD_DL_LINKMAP) || !map || !map->l_name) + return h25_loader_error("Resolved symbol has no admitted native provider map"); + size_t found = H25_MAP_CAP; + for (size_t i = 0; i < h25_loader_before.count; ++i) { + H25MapRecord *candidate = &h25_loader_before.maps[i]; + if (candidate->base == (uint64_t)map->l_addr && !strcmp(candidate->name, map->l_name)) { + if (found != H25_MAP_CAP) + return h25_loader_error("Resolved symbol provider map is ambiguous"); + found = i; + } + } + if (found == H25_MAP_CAP) + return h25_loader_error("Resolved symbol provider is absent from captured maps"); + H25MapRecord *provider = &h25_loader_before.maps[found]; + uint64_t location = (uint64_t)(uintptr_t)address; + int in_segment = 0; + for (size_t i = 0; i < provider->segment_count; ++i) { + if (location >= provider->segments[i].lo && location < provider->segments[i].hi) + in_segment = 1; + } + if (!in_segment) + return h25_loader_error("Resolved symbol is outside provider PT_LOAD ranges"); + result->address = location; + result->provider_base = provider->base; + result->provider_name = provider->name; + const ElfW(Sym) *address_symbol = NULL; + if (dladdr1(address, &info, (void **)&address_symbol, RTLD_DL_SYMENT) && + address_symbol && info.dli_saddr) { + result->has_address_symbol = 1; + result->address_symbol_type = ELF64_ST_TYPE(address_symbol->st_info); + result->address_symbol_address = (uint64_t)(uintptr_t)info.dli_saddr; + } + /* This last metadata describes only a nearest address symbol, potentially + * absent for hidden IFUNC implementation code. It is not a definition, + * resolver, binding or symbol-version assertion. */ + return 0; +} + +static void +h25_loader_forget_request_pointers(void) +{ + /* Request strings are borrowed only during the call, never retained. */ + for (size_t i = 0; i < H25_SYMBOL_CAP; ++i) { + h25_loader_symbols[i].name = NULL; + h25_loader_symbols[i].version = NULL; + h25_loader_symbols[i].provider_name = NULL; + } +} + +static PyObject * +probe_field_loader_snapshot(PyObject *module, PyObject *requests) +{ + if (h25_loader_module_check(module) < 0) + return NULL; + if (!h25_loader_maps_ready || h25_loader_symbols_attempted) { + h25_loader_error("Loader symbol capture requires successful maps and one attempt"); + return NULL; + } + h25_loader_symbols_attempted = 1; + Py_ssize_t count = 0; + PyObject *result = NULL; + if (h25_loader_requests(requests, &count) < 0 || + h25_loader_take_maps(&h25_loader_before) < 0 || h25_loader_namespace() < 0) + goto done; + if (!h25_loader_same_maps(&h25_loader_baseline, &h25_loader_before)) { + h25_loader_error("Loaded map history changed before symbol resolution"); + goto done; + } + for (Py_ssize_t i = 0; i < count; ++i) { + if (h25_loader_resolve(&h25_loader_symbols[i]) < 0) + goto done; + } + if (h25_loader_take_maps(&h25_loader_after) < 0) + goto done; + if (!h25_loader_same_maps(&h25_loader_before, &h25_loader_after)) { + h25_loader_error("Symbol resolution changed loaded maps"); + goto done; + } + result = h25_loader_result(requests, count); +done: + h25_loader_forget_request_pointers(); + return result; +} + +#endif diff --git a/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/field_service_v1.h.txt b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/field_service_v1.h.txt new file mode 100644 index 0000000000..48e7edb334 --- /dev/null +++ b/research/h25-c05-source-roots/snapshot/areas/field-negative-variants-v1/pyinit_failure/field_service_v1.h.txt @@ -0,0 +1,428 @@ +/* Additive indexed field transport. SOURCE ONLY; no runtime admission. + * Original getter/id semantics: CPython 3.12.3 descrobject.c, funcobject.c, + * bltinmodule.c; attribution/license remain in the unchanged probe sources. + * No function-field structure access and no address-derived field IDs. + */ +#ifndef H25_FIELD_SERVICE_V1_H +#define H25_FIELD_SERVICE_V1_H + +#define H25_FIELD_MAGIC UINT64_C(0x4832354649454c44) +#define H25_FIELD_COUNT 7 +/* Concrete source-fixed pointer-table profile consumed by the separate ELF + * parser. These become compiler gates, not evidence of a current binary. */ +_Static_assert(sizeof(PyMethodDef) == 32, "field method table entry size"); +_Static_assert(sizeof(PyModuleDef) == 104, "field module definition size"); +_Static_assert(sizeof(PyModuleDef_Slot) == 16, "field module slot size"); +_Static_assert(offsetof(PyModuleDef, m_traverse) == 80, "module traverse offset"); +_Static_assert(offsetof(PyModuleDef, m_clear) == 88, "module clear offset"); +_Static_assert(offsetof(PyModuleDef, m_free) == 96, "module free offset"); +_Static_assert(offsetof(PyTypeObject, tp_dealloc) == 48, "context dealloc offset"); +_Static_assert(offsetof(PyTypeObject, tp_traverse) == 184, "context traverse offset"); +_Static_assert(offsetof(PyTypeObject, tp_clear) == 192, "context clear offset"); +enum { + H25_FIELD_UNBOUND = 0, H25_FIELD_BOUND = 1, H25_FIELD_CLOSING = 2, + H25_FIELD_CLOSED = 3, H25_FIELD_FAILED = 4 +}; + +typedef struct { + uint64_t magic; + int initialized, phase, bind_attempted, clear_pending, close_authorized; + int64_t interpreter_id; + Py_ssize_t active; + /* These are the only persistent Python roots. No targets or observations. */ + PyObject *getters[H25_FIELD_COUNT]; + PyObject *id0, *function_type, *close_token; +} H25FieldState; + +typedef struct { + PyObject_HEAD + H25FieldState state; +} H25FieldContext; +_Static_assert(sizeof(H25FieldState) == 128, "field primitive state size"); +_Static_assert(sizeof(H25FieldContext) == 144, "field fixture allocation size"); + +static struct PyModuleDef h25_field_module; +static PyTypeObject h25_field_context_type; +static unsigned int h25_field_context_created; +static int h25_field_exec_attempted; +#define H25_FIELD_CONTEXT_CAP 64u + +static H25FieldState * +h25_field_raw_state(PyObject *owner) +{ + if (Py_IS_TYPE(owner, &h25_field_context_type)) + return &((H25FieldContext *)owner)->state; + if (PyModule_CheckExact(owner) && PyModule_GetDef(owner) == &h25_field_module) + return (H25FieldState *)PyModule_GetState(owner); + return NULL; +} + +/* Clear each slot before decref. The token is an exact plain object, and the + * other roots are original builtin primitives, so cleanup adds no candidate + * finalizer. Keep token after logical close for authenticated idempotence. */ +static void +h25_field_drop_roots(H25FieldState *state, int drop_token) +{ + for (int i = 0; i < H25_FIELD_COUNT; ++i) + Py_CLEAR(state->getters[i]); + Py_CLEAR(state->id0); + Py_CLEAR(state->function_type); + if (drop_token) + Py_CLEAR(state->close_token); +} + +static H25FieldState * +h25_field_state(PyObject *module) +{ + H25FieldState *state = h25_field_raw_state(module); + if (!state) { + PyErr_SetString(PyExc_RuntimeError, "Field service owner changed"); + return NULL; + } + if (!state || !state->initialized || state->magic != H25_FIELD_MAGIC || + !PyGILState_Check() || Py_Version != (unsigned long)PY_VERSION_HEX || + state->interpreter_id != 0 || + PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())) != state->interpreter_id || + state->active < 0 || state->phase < H25_FIELD_UNBOUND || + state->phase > H25_FIELD_FAILED) { + PyErr_SetString(PyExc_RuntimeError, "Field service native state unavailable"); + return NULL; + } + return state; +} + +static PyObject * +h25_field_bind(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + H25FieldState *state = h25_field_state(module); + if (!state) + return NULL; + if (state->bind_attempted || state->phase != H25_FIELD_UNBOUND || + state->active || state->clear_pending) { + PyErr_SetString(PyExc_RuntimeError, "Field primitive binding is single-use"); + return NULL; + } + /* Failed first binding is terminal; there is no partial registration. */ + state->bind_attempted = 1; + state->phase = H25_FIELD_FAILED; + if (nargs != 4 || !PyTuple_CheckExact(args[0]) || + PyTuple_GET_SIZE(args[0]) != H25_FIELD_COUNT || + !PyCFunction_CheckExact(args[1]) || + PyCFunction_GET_FLAGS(args[1]) != METH_O || + args[2] != (PyObject *)&PyFunction_Type || + !Py_IS_TYPE(args[3], &PyBaseObject_Type)) { + PyErr_SetString(PyExc_TypeError, "Field binding requires exact original primitive packet"); + return NULL; + } + for (int i = 0; i < H25_FIELD_COUNT; ++i) { + if (!Py_IS_TYPE(PyTuple_GET_ITEM(args[0], i), &_PyMethodWrapper_Type)) { + PyErr_SetString(PyExc_TypeError, "Field getter must be an original bound method-wrapper"); + return NULL; + } + } + /* Root authenticates each object's identity and descriptor ownership before + * this call. The native type checks above are not substitute provenance. */ + for (int i = 0; i < H25_FIELD_COUNT; ++i) + state->getters[i] = Py_NewRef(PyTuple_GET_ITEM(args[0], i)); + state->id0 = Py_NewRef(args[1]); + state->function_type = Py_NewRef(args[2]); + state->close_token = Py_NewRef(args[3]); + state->phase = H25_FIELD_BOUND; + Py_RETURN_NONE; +} + +static void +h25_field_leave(H25FieldState *state) +{ + /* Each successful enter has exactly one leave, with the GIL continuously + * held apart from original getter/id callbacks' own behavior. */ + --state->active; + if (state->active == 0) { + if (state->clear_pending) { + state->phase = H25_FIELD_FAILED; + h25_field_drop_roots(state, 1); + } + else if (state->phase == H25_FIELD_CLOSING) { + state->phase = H25_FIELD_CLOSED; + h25_field_drop_roots(state, 0); + } + } +} + +static PyObject * +h25_field_id(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + H25FieldState *state = h25_field_state(module); + if (!state) + return NULL; + if (nargs != 2 || !PyFunction_Check(args[0]) || !PyLong_CheckExact(args[1])) { + PyErr_SetString(PyExc_TypeError, "field_id requires exact function and integer index"); + return NULL; + } + long index = PyLong_AsLong(args[1]); + if (index == -1 && PyErr_Occurred()) + return NULL; + if (index < 0 || index >= H25_FIELD_COUNT) { + PyErr_SetString(PyExc_IndexError, "field_id index must be in 0..6"); + return NULL; + } + if ((state->phase == H25_FIELD_CLOSING || state->phase == H25_FIELD_CLOSED) && + state->close_authorized && state->close_token && !state->clear_pending) { + /* Exact None can never be an original builtin id result. Root must + * independently witness legitimate CLOSING/CLOSED before fallback. */ + Py_RETURN_NONE; + } + if (state->phase != H25_FIELD_BOUND || state->clear_pending || + !state->bind_attempted || state->close_authorized || !state->close_token || + !state->getters[index] || !state->id0 || + state->function_type != (PyObject *)&PyFunction_Type) { + PyErr_SetString(PyExc_RuntimeError, "Field service is not bound and active"); + return NULL; + } + if (state->active == PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, "Field service active-call bound exhausted"); + return NULL; + } + /* Acquire every call root before the first observable field event. Neither + * a legitimate close nor GC clear may release state while active != 0. */ + PyObject *owner = Py_NewRef(module); + PyObject *getter = Py_NewRef(state->getters[index]); + PyObject *id0 = Py_NewRef(state->id0); + PyObject *function_type = Py_NewRef(state->function_type); + ++state->active; + PyObject *getter_args[2] = {args[0], function_type}; + PyObject *temporary = PyObject_Vectorcall(getter, getter_args, 2, NULL); + PyObject *result = NULL; + PyObject *error = NULL; + if (temporary) { + /* The original builtin id is invoked even after a legitimate close + * inside the getter. No direct field read, pointer-ID shortcut, retry + * or other field lookup occurs here. */ + result = PyObject_CallOneArg(id0, temporary); + if (!result) + error = PyErr_GetRaisedException(); + /* This is the original expression's temporary-release point. An id + * audit may have detached the field, making this its last reference. + * Its finalizer must run BEFORE return/Python's expected comparison. */ + Py_DECREF(temporary); + } + else { + error = PyErr_GetRaisedException(); + } + h25_field_leave(state); + Py_DECREF(function_type); + Py_DECREF(id0); + Py_DECREF(getter); + /* No state access after owner DECREF. */ + Py_DECREF(owner); + if (!result) + PyErr_SetRaisedException(error); + return result; +} + +static PyObject * +h25_field_close(PyObject *module, PyObject *token) +{ + H25FieldState *state = h25_field_state(module); + if (!state) + return NULL; + if (!state->close_token || token != state->close_token || state->clear_pending || + (state->phase != H25_FIELD_BOUND && state->phase != H25_FIELD_CLOSING && + state->phase != H25_FIELD_CLOSED)) { + PyErr_SetString(PyExc_RuntimeError, "Field close lacks the original owner token"); + return NULL; + } + state->close_authorized = 1; + state->phase = state->active ? H25_FIELD_CLOSING : H25_FIELD_CLOSED; + if (!state->active) + h25_field_drop_roots(state, 0); + Py_RETURN_NONE; +} + +static PyObject * +h25_field_status(PyObject *module, PyObject *unused) +{ + (void)unused; + H25FieldState *state = h25_field_state(module); + if (!state) + return NULL; + return Py_BuildValue("(iiniL)", 1, state->phase, state->active, + state->bind_attempted, (long long)state->interpreter_id); +} + +static PyObject * +h25_field_abi(PyObject *module, PyObject *unused) +{ + (void)unused; + if (!h25_field_state(module)) + return NULL; + return Py_BuildValue("(iiiii)", 1, H25_FIELD_COUNT, PY_VERSION_HEX, + (int)sizeof(void *), 2); +} + +static int +h25_field_traverse(PyObject *module, visitproc visit, void *arg) +{ + H25FieldState *state = h25_field_raw_state(module); + if (!state) + return 0; + for (int i = 0; i < H25_FIELD_COUNT; ++i) + Py_VISIT(state->getters[i]); + Py_VISIT(state->id0); + Py_VISIT(state->function_type); + Py_VISIT(state->close_token); + return 0; +} + +static int +h25_field_clear(PyObject *module) +{ + H25FieldState *state = h25_field_raw_state(module); + if (!state) + return 0; + state->clear_pending = 1; + state->phase = H25_FIELD_FAILED; + if (!state->active) + h25_field_drop_roots(state, 1); + return 0; +} + +static void +h25_field_free(void *module) +{ + /* An active call owns a strong module reference, so module deallocation + * cannot occur during that call. clear remains separately safe/deferred. */ + (void)h25_field_clear((PyObject *)module); + H25FieldState *state = h25_field_raw_state((PyObject *)module); + if (state) + state->magic = 0; +} + +static void +h25_field_context_dealloc(PyObject *context) +{ + /* An active field owns its context just as it owns the primary module. */ + PyObject_GC_UnTrack(context); + (void)h25_field_clear(context); + ((H25FieldContext *)context)->state.magic = 0; + PyObject_GC_Del(context); +} + +static PyObject * +h25_field_new_context(PyObject *module, PyObject *unused) +{ + (void)unused; + if (!PyModule_CheckExact(module) || PyModule_GetDef(module) != &h25_field_module || + !h25_field_state(module)) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_RuntimeError, "Field context factory requires original service module"); + return NULL; + } + if (h25_field_context_created >= H25_FIELD_CONTEXT_CAP) { + PyErr_SetString(PyExc_OverflowError, "Field fixture context bound exhausted"); + return NULL; + } + /* Count attempts, including allocation failure; no silent fixture retry. */ + ++h25_field_context_created; + H25FieldContext *context = PyObject_GC_New(H25FieldContext, &h25_field_context_type); + if (!context) + return NULL; + context->state = (H25FieldState){0}; + context->state.magic = H25_FIELD_MAGIC; + context->state.interpreter_id = 0; + context->state.initialized = 1; + context->state.phase = H25_FIELD_UNBOUND; + PyObject_GC_Track(context); + return (PyObject *)context; +} + +static int +h25_field_exec(PyObject *module) +{ + H25FieldState *state = (H25FieldState *)PyModule_GetState(module); + if (!state) + return -1; + if (h25_field_exec_attempted || state->initialized || !PyGILState_Check() || + Py_Version != (unsigned long)PY_VERSION_HEX) { + PyErr_SetString(PyExc_ImportError, "Field service initialization profile rejected"); + return -1; + } + h25_field_exec_attempted = 1; + int64_t interpreter_id = + PyInterpreterState_GetID(PyThreadState_GetInterpreter(PyThreadState_Get())); + if (interpreter_id != 0) { + PyErr_SetString(PyExc_ImportError, "Field service requires the original main interpreter"); + return -1; + } + if (PyType_Ready(&h25_field_context_type) < 0) + return -1; + state->magic = H25_FIELD_MAGIC; + state->interpreter_id = interpreter_id; + state->initialized = 1; + state->phase = H25_FIELD_UNBOUND; + return 0; +} + +static PyMethodDef h25_field_methods[] = { + {"field_id", (PyCFunction)(void(*)(void))h25_field_id, METH_FASTCALL, "One original getter/id event pair, with original temporary disposal."}, + {"_bind_fields", (PyCFunction)(void(*)(void))h25_field_bind, METH_FASTCALL, "Bind the authenticated original primitive packet exactly once."}, + {"_close_fields", h25_field_close, METH_O, "Logical close with original private token; active field completes once."}, + {"_field_status", h25_field_status, METH_NOARGS, "Native phase and active count; no target observations."}, + {"_field_abi", h25_field_abi, METH_NOARGS, "Immutable indexed-field interface profile."}, + {"_new_field_context", h25_field_new_context, METH_NOARGS, "Create one independently bound fixture context in this same image."}, + {NULL, NULL, 0, NULL} +}; +/* Separate table deliberately omits the factory: fixtures cannot manufacture + * other fixtures or reach mutable module storage. Methods remain native + * immutable PyCFunction objects strongly owning their actual context. */ +static PyMethodDef h25_field_context_methods[] = { + {"field_id", (PyCFunction)(void(*)(void))h25_field_id, METH_FASTCALL, "One original getter/id event pair, with original temporary disposal."}, + {"_bind_fields", (PyCFunction)(void(*)(void))h25_field_bind, METH_FASTCALL, "Bind the authenticated original primitive packet exactly once."}, + {"_close_fields", h25_field_close, METH_O, "Logical close with original private token; active field completes once."}, + {"_field_status", h25_field_status, METH_NOARGS, "Native phase and active count; no target observations."}, + {"_field_abi", h25_field_abi, METH_NOARGS, "Immutable indexed-field interface profile."}, + {NULL, NULL, 0, NULL} +}; +static PyTypeObject h25_field_context_type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "_h25_field_service_v1._FieldContext", + .tp_basicsize = sizeof(H25FieldContext), + .tp_dealloc = h25_field_context_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .tp_traverse = h25_field_traverse, + .tp_clear = h25_field_clear, + .tp_methods = h25_field_context_methods, + .tp_doc = "One-shot fixture primitive owner; no dictionary, target roots or reload." +}; +static PyModuleDef_Slot h25_field_slots[] = { + {Py_mod_exec, h25_field_exec}, + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + {0, NULL} +}; +static struct PyModuleDef h25_field_module = { + PyModuleDef_HEAD_INIT, + "_h25_field_service_v1", + "Source-bound indexed original-primitive transport without target retention.", + sizeof(H25FieldState), + h25_field_methods, + h25_field_slots, + h25_field_traverse, h25_field_clear, h25_field_free +}; +PyMODINIT_FUNC +PyInit__h25_field_service_v1(void) +{ + /* H25_NEGATIVE_FIXTURE_PYINIT_V1: this separate paid fixture reaches the + * original module-definition prefix before its deliberate failure. The + * static PyModuleDef result has no newly acquired heap reference to drop. + * Passing its address to the original external API keeps the definition + * graph source-reachable; actual compiled tables still require ELF checks. + */ + PyObject *definition = PyModuleDef_Init(&h25_field_module); + if (definition == NULL) + return NULL; /* Preserve a genuine original prefix failure. */ + PyErr_SetString(PyExc_ImportError, + "H25 negative pyinit fixture: deliberate failure after module definition initialization"); + return NULL; +} + +#endif diff --git a/research/h25-c05-source-roots/snapshot/areas/field-variant-producer-v2/CONDITIONS.json b/research/h25-c05-source-roots/snapshot/areas/field-variant-producer-v2/CONDITIONS.json new file mode 100644 index 0000000000..fee8188ea8 --- /dev/null +++ b/research/h25-c05-source-roots/snapshot/areas/field-variant-producer-v2/CONDITIONS.json @@ -0,0 +1,108 @@ +{ + "additional_review_boundaries_preserved": [ + "The receiver32MiB aggregate limit is an admission check before parsing, not proof of a producer-wide disk/resource reservation.", + "Native I/O roots protect the first successfully delivered error under stated interpreter/private-state premises; inherited helper/TCB/cold-authority formatting, allocation and pre-delivery/unwind remain unqualified.", + "Parent alone supplies current launch/stage/source/terminal/domain/custody authority; child zero counters and JSON status are not that authority.", + "All25 recipe controls, full original/additive runtime union, complete configured closure, funding and execution remain open." + ], + "conditions": [ + { + "discharged_by_this_source_packet": false, + "id": "C01", + "required": "Actual parent authenticates pristine original f5 Root/API4/provider, interpreter flags/env/native startup and original native TCB profile before launch; no alternative Root or candidate bootstrap." + }, + { + "discharged_by_this_source_packet": false, + "id": "C02", + "required": "Configured successor and full installed stage receive independent source/command/review admission. Driver and receiver constants remain None here; literal configuration is never obtained from child raw data." + }, + { + "discharged_by_this_source_packet": false, + "id": "C03", + "required": "Preserve original six integration admissions and original helper/native packet bytes. Retain exact two extra control-name builds, role order, no retry, no positive triple rebuild and zero variant loads." + }, + { + "discharged_by_this_source_packet": false, + "id": "C04", + "required": "Install all six reviewed C/header variant bytes with literal hashes/sizes0444 adjacent at the source-fixed role paths. Preserve ImportError/RuntimeError and earlier failure behavior from review643892da." + }, + { + "discharged_by_this_source_packet": false, + "id": "C05", + "required": "Complete current project/system header, include search, macro, compiler, specs, linker and dependent-library witness closure must be independently approved and included in bounded source_files. Original dependency scan alone is insufficient." + }, + { + "discharged_by_this_source_packet": false, + "id": "C06", + "required": "Independently fix both complete ELFv2 static policies including required production method rows/data slots, all source/compiler/link profiles and exact changed-header bindings. Only actual build receipt SHA is populated after capture. No expected ELF answer may be learned from output." + }, + { + "discharged_by_this_source_packet": false, + "id": "C07", + "required": "Parent owns output ancestors and immutable source/stage directories. Leaf nofollow is not protection against mutable ancestor substitution. Parent verifies the full stage/driver/receiver separately before/after; child literal closure avoids self hashes." + }, + { + "discharged_by_this_source_packet": false, + "id": "C08", + "required": "Parent current receiver closure authenticates original module/function/default/builtin/source identities before and after direct validation, including exact ELFv2. Never call through an unverified arbitrary reader/checker." + }, + { + "discharged_by_this_source_packet": false, + "id": "C09", + "required": "Parent supplies actual Popen PID, generation/nonce/mode/argv and independent expected plan, reads all26 fixed current files with own identity/custody, corroborates stdout and final receipt, and alone creates terminal/ParentCompletion/epoch authority." + }, + { + "discharged_by_this_source_packet": false, + "id": "C10", + "required": "Bounded adapter I/O proof begins at first successfully delivered bound error with protected exact-list slots, original native primitives, no concurrent/async/tracing/hostile-finalizer interference and adequate delivery/unwind. Pending acquisition quarantines all new I/O; uncertain descriptors remain for parent teardown." + }, + { + "discharged_by_this_source_packet": false, + "id": "C11", + "required": "Inherited original helper/TCB/cold-authority allocation, formatting, cleanup and pre-handler-delivery errors remain unqualified. Outer capture cannot recover a prior replaced error. New local-slot proof is not whole-handler MemoryError or all-control admission." + }, + { + "discharged_by_this_source_packet": false, + "id": "C12", + "required": "Retain all raw/attempt/journal/log/partial files without overwrite/rebuild/delete. Missing/failed capture or close is STOP/incomplete, never inferred success. A returned helper object held only in process is not durable evidence." + }, + { + "discharged_by_this_source_packet": false, + "id": "C13", + "required": "Run the bounded source/control recipes in a separately approved fresh stage; preserve every failure and both execution modes. No target calls or tests occurred here." + }, + { + "discharged_by_this_source_packet": false, + "id": "C14", + "required": "Fund the complete cost and ordinary/negative/full-caller resource controls independently. This source implementation grants no execution, performance, runtime/bootstrap, scientific or final202-control admission." + }, + { + "discharged_by_this_source_packet": false, + "id": "C15", + "required": "Independently review exact-type comparator and all comparison replacements, gates before imports, exact V1/source inverses and additive type-substitution controls. Float values remain outside the original integer-only JSON domain. No target execution has qualified this source." + } + ], + "configuration": null, + "control_count_note": "The V1 review preserved all25 original recipe obligations; V2 adds8, total33 unexecuted. Receiver32MiB is an admission/parsing bound, not a producer-wide disk or resource reservation.", + "execution": null, + "parent_gate_boundary": "Current parent-completion source independently checks exact dictionaries/digests before either producer; these are externally authenticated bootstrap records, never child JSON authority. Parent V1 frozen source requires new version/review to adopt this V2 validator.", + "parent_gate_schema": { + "VALIDATION_CONFIGURATION": [ + "leaf_policy_sha256", + "configuration_sha256" + ], + "VALIDATION_EXECUTION": [ + "external_launch_policy_sha256" + ], + "VALIDATION_FUNDING": [ + "reservation_sha256" + ], + "VALIDATION_SOURCE_REVIEW": [ + "review_sha256" + ] + }, + "schema": "h25-negative-variant-producer-conditions-v2", + "source_only": true, + "v1_independent_conditions_sha256": "c844cc035df70c73223c3066d9f1f57aed2e5a37bc5fab580b0d890009ab8997", + "v1_independent_review_sha256": "978151bbce51a4ece02264cde8e8b5fcf170612d35c984246640485afbc9f22d" +} diff --git a/research/h25-c05-source-roots/snapshot/areas/field-variant-producer-v2/variant_driver_v1.py.txt b/research/h25-c05-source-roots/snapshot/areas/field-variant-producer-v2/variant_driver_v1.py.txt new file mode 100644 index 0000000000..bfd9b735f6 --- /dev/null +++ b/research/h25-c05-source-roots/snapshot/areas/field-variant-producer-v2/variant_driver_v1.py.txt @@ -0,0 +1,819 @@ +#!/usr/bin/env python3 +"""Build-only two-role negative producer; unconfigured source draft. + +Original f5 Root/API4, initial five and cold authority are retained. No image +is loaded. Parent source/native/process/resource/whole-caller gates stay open. +""" +from __future__ import annotations + +# Actual source-authenticated root injects these three values before driver exec. +# Capture them before importing any candidate, scientific, or orchestration code. +_CAPTURED_BOOTSTRAP_ROOT = bootstrap_root +_CAPTURED_BOOTSTRAP_CAPABILITY = bootstrap_capability +_CAPTURED_BOOTSTRAP_API = bootstrap_api +if type(_CAPTURED_BOOTSTRAP_API) is not tuple or len(_CAPTURED_BOOTSTRAP_API) != 4: + raise RuntimeError('Driver requires the parent-sealed exact four-entry bootstrap API') +_INITIAL_ROOT_IDENTITY = _CAPTURED_BOOTSTRAP_API[0]() +if (type(_CAPTURED_BOOTSTRAP_ROOT) is not _CAPTURED_BOOTSTRAP_ROOT.ModuleType or + any(type(entry) is not _CAPTURED_BOOTSTRAP_ROOT.FunctionType or + entry.__globals__ is not _CAPTURED_BOOTSTRAP_ROOT.__dict__ + for entry in _CAPTURED_BOOTSTRAP_API)): + raise RuntimeError('Driver bootstrap API is not bound to the actual root namespace') + +# SOURCE-ONLY: configuring these literals requires a separately reviewed successor. +VARIANT_CONFIGURATION = None +VARIANT_SOURCE_REVIEW = None +VARIANT_STAGE_ADMISSION = None +VARIANT_NATIVE_PROFILE = None +VARIANT_HEADER_ADMISSION = None +VARIANT_COMMAND_ADMISSION = None +VARIANT_FUNDING = None +VARIANT_EXECUTION = None +if any(value is None for value in (VARIANT_CONFIGURATION, VARIANT_SOURCE_REVIEW, + VARIANT_STAGE_ADMISSION, VARIANT_NATIVE_PROFILE, VARIANT_HEADER_ADMISSION, + VARIANT_COMMAND_ADMISSION, VARIANT_FUNDING, VARIANT_EXECUTION)): + raise RuntimeError('Negative variant producer is unconfigured; execution withheld') + +# Allocated before the first protected I/O. Slots never recycle an error. +# [first delivered primary, first secondary, quarantined, pending open, owned FD] +_VARIANT_IO = [None, None, False, False, None] +_VARIANT_RETURNS = [None, None] +_VARIANT_TERMINAL_ERROR = [None] +_VARIANT_USED = [False, False] +_VARIANT_WIRE_LIMIT = 1048576 + + +_VARIANT_POSIX_NAMES = ('open', 'read', 'fstat', 'close', 'write', 'fsync', 'mkdir') +_VARIANT_POSIX = tuple(_CAPTURED_BOOTSTRAP_ROOT.posix.__dict__[name] for name in _VARIANT_POSIX_NAMES) +_VARIANT_READ_FLAGS = (_CAPTURED_BOOTSTRAP_ROOT.posix.O_RDONLY | + _CAPTURED_BOOTSTRAP_ROOT.posix.O_NOFOLLOW | _CAPTURED_BOOTSTRAP_ROOT.posix.O_CLOEXEC) +_VARIANT_WRITE_FLAGS = (_CAPTURED_BOOTSTRAP_ROOT.posix.O_WRONLY | + _CAPTURED_BOOTSTRAP_ROOT.posix.O_CREAT | _CAPTURED_BOOTSTRAP_ROOT.posix.O_EXCL | + _CAPTURED_BOOTSTRAP_ROOT.posix.O_NOFOLLOW | _CAPTURED_BOOTSTRAP_ROOT.posix.O_CLOEXEC) + + +def _vops(): + _CAPTURED_BOOTSTRAP_API[0]() + root = _CAPTURED_BOOTSTRAP_ROOT + module = root.posix + for name, function in zip(_VARIANT_POSIX_NAMES, _VARIANT_POSIX): + if (type(function) is not root.BuiltinFunctionType or function.__self__ is not module or + function.__name__ != name or module.__dict__.get(name) is not function): + raise RuntimeError('Variant original POSIX primitive differs') + if (_VARIANT_POSIX[0] is not root._OPEN or _VARIANT_POSIX[1] is not root._READ or + _VARIANT_POSIX[2] is not root._FSTAT or _VARIANT_POSIX[3] is not root._CLOSE): + raise RuntimeError('Variant POSIX original Root aliases differ') + return _VARIANT_POSIX + + +def _vsame(left, right): + """Bounded exact native tree equality; no coercion or foreign callbacks. + + The existing producer/receiver JSON domain is integer-only: floats, including + finite floats, remain rejected. Bytes are supported only as exact byte leaves. + Dictionary field sets are unordered; list and tuple order and kind are exact. + The caller cannot supply the private budget or a comparison callback. + """ + budget = [0, 0, 0] # paired nodes, both-side text, both-side bytes + + def walk(a, b, depth): + budget[0] += 1 + if depth > 24 or budget[0] > 65536: + return False + kind = type(a) + if kind is not type(b): + return False + if a is None: + return True + if kind is bool: + return a is b + if kind is int: + if not -(1 << 64) <= a < (1 << 64) or not -(1 << 64) <= b < (1 << 64): + return False + return a == b + if kind is str: + if len(a) > 8192 or len(b) > 8192: + return False + budget[1] += len(a) + len(b) + if budget[1] > 1048576: + return False + return a == b + if kind is bytes: + if len(a) > 8388608 or len(b) > 8388608: + return False + budget[2] += len(a) + len(b) + if budget[2] > 33554432: + return False + return a == b + if kind is list or kind is tuple: + if len(a) > 1024 or len(b) > 1024 or len(a) != len(b): + return False + index = 0 + while index < len(a): + if not walk(a[index], b[index], depth + 1): + return False + index += 1 + return True + if kind is dict: + if len(a) > 1024 or len(b) > 1024 or len(a) != len(b): + return False + # Complete both key-domain walks before membership or lookup. Exact + # str keys use native hashing/equality; no unknown key gets hashed. + for key in a: + if type(key) is not str or len(key) > 8192: + return False + budget[1] += len(key) + if budget[1] > 1048576: + return False + for key in b: + if type(key) is not str or len(key) > 8192: + return False + budget[1] += len(key) + if budget[1] > 1048576: + return False + for key in a: + if key not in b: + return False + if not walk(a[key], b[key], depth + 1): + return False + return True + # Includes float, all subclasses, user objects and callable values. + return False + + return walk(left, right, 0) + + +def _vplain(value, depth=0, budget=None): + # Exact native values only. No repr/str of unknown objects or error objects. + if budget is None: + budget = [0, 0] + budget[0] += 1 + if depth > 24 or budget[0] > 65536: + raise RuntimeError('Variant raw object bound exceeded') + if value is None or type(value) is bool: + return value + if type(value) is int: + if not -(1 << 64) <= value < (1 << 64): + raise RuntimeError('Variant integer bound exceeded') + return value + if type(value) is str: + budget[1] += len(value) + if len(value) > 8192 or budget[1] > 524288: + raise RuntimeError('Variant string bound exceeded') + return value + if type(value) in (list, tuple): + if len(value) > 1024: + raise RuntimeError('Variant sequence bound exceeded') + return [_vplain(item, depth + 1, budget) for item in value] + if type(value) is dict: + if len(value) > 1024: + raise RuntimeError('Variant mapping bound exceeded') + for key in value: + if type(key) is not str: + raise RuntimeError('Variant foreign mapping key') + _vplain(key, depth + 1, budget) + return {key: _vplain(value[key], depth + 1, budget) for key in value} + raise RuntimeError('Variant foreign raw value') + + +def _vencode(value): + # Before cold capture no imports are added. Exact strings are escaped as ASCII JSON. + value = _vplain(value) + def emit(item): + if item is None: + return 'null' + if type(item) is bool: + return 'true' if item else 'false' + if type(item) is int: + return str(item) + if type(item) is str: + parts = ['"'] + for c in item: + if c == '"': + parts.append('\\"') + elif c == '\\': + parts.append('\\\\') + elif ord(c) < 32 or ord(c) >= 127: + code = ord(c) + if code <= 65535: + parts.append('\\u%04x' % code) + else: + code -= 65536 + parts.append('\\u%04x\\u%04x' % (55296 + (code >> 10), 56320 + (code & 1023))) + else: + parts.append(c) + parts.append('"') + return ''.join(parts) + if type(item) is list: + return '[' + ','.join(emit(x) for x in item) + ']' + return '{' + ','.join(emit(k) + ':' + emit(item[k]) for k in sorted(item)) + '}' + result = (emit(value) + '\n').encode('ascii') + if len(result) > _VARIANT_WIRE_LIMIT: + raise RuntimeError('Variant wire bound exceeded') + return result + + +def _vwrite(path, raw): + # Pending-open quarantine covers an unreturned possible descriptor. It does + # not prove release; parent process teardown must close an uncertain FD. + state = _VARIANT_IO + if state[2] or state[3] or state[4] is not None: + raise RuntimeError('Variant I/O quarantined') + if type(raw) is not bytes or len(raw) > _VARIANT_WIRE_LIMIT: + raise RuntimeError('Variant write bound differs') + ops = _vops() + open0, write0, sync0, close0 = ops[0], ops[4], ops[5], ops[3] + flags = _VARIANT_WRITE_FLAGS + primary = secondary = None + try: + state[3] = True + state[4] = open0(path, flags, 0o600) + state[3] = False + offset = calls = 0 + while offset < len(raw): + if calls >= 4096: + raise RuntimeError('Variant write call bound exceeded') + count = write0(state[4], raw[offset:offset + 65536]) + if type(count) is not int or count <= 0: + raise RuntimeError('Variant write made no progress') + offset += count + calls += 1 + sync0(state[4]) + except BaseException as error: + # Inline first bind before any allocating helper/call/formatting. + primary = error + state[0] = error + state[2] = True + finally: + if state[4] is not None: + descriptor = state[4] + state[4] = None + try: + close0(descriptor) + except BaseException as error: + secondary = error + state[1] = error + state[2] = True + if primary is not None: + raise primary + if secondary is not None: + raise secondary + + +def _vraw(path, value): + # Caller roots the returned object before entering this allocating encoder. + _vwrite(path, _vencode(value)) + + +def _vread(path, limit): + state = _VARIANT_IO + if state[2] or state[3] or state[4] is not None: + raise RuntimeError('Variant I/O quarantined') + if type(limit) is not int or not 0 < limit <= 67108864: + raise RuntimeError('Variant read bound differs') + ops = _vops() + open0, read0, stat0, close0 = ops[0], ops[1], ops[2], ops[3] + primary = secondary = None + result = before = after = None + try: + state[3] = True + state[4] = open0(path, _VARIANT_READ_FLAGS) + state[3] = False + before = stat0(state[4]) + if before.st_mode & 0o170000 != 0o100000 or before.st_size > limit: + raise RuntimeError('Variant file type or size differs') + blocks, total, calls = [], 0, 0 + while True: + if calls >= 4096: + raise RuntimeError('Variant read call bound exceeded') + block = read0(state[4], min(65536, limit + 1 - total)) + calls += 1 + if not block: + break + blocks.append(block) + total += len(block) + if total > limit: + raise RuntimeError('Variant file grew past bound') + after = stat0(state[4]) + if ((before.st_dev, before.st_ino, before.st_mode, before.st_size, + before.st_mtime_ns, before.st_ctime_ns) != + (after.st_dev, after.st_ino, after.st_mode, after.st_size, + after.st_mtime_ns, after.st_ctime_ns) or total != after.st_size): + raise RuntimeError('Variant file changed during read') + result = b''.join(blocks) + except BaseException as error: + primary = error + state[0] = error + state[2] = True + finally: + if state[4] is not None: + descriptor = state[4] + state[4] = None + try: + close0(descriptor) + except BaseException as error: + secondary = error + state[1] = error + state[2] = True + if primary is not None: + raise primary + if secondary is not None: + raise secondary + return result, after + + +def _vstdout(raw): + # Descriptor 1 is borrowed from the owning parent and is never closed here. + # receipt.json already exists before this terminal mirror is attempted. + state = _VARIANT_IO + if state[2] or state[3] or state[4] is not None: + raise RuntimeError('Variant stdout after I/O quarantine') + if type(raw) is not bytes or len(raw) > _VARIANT_WIRE_LIMIT: + raise RuntimeError('Variant stdout bound differs') + write0 = _vops()[4] + try: + offset = calls = 0 + while offset < len(raw): + if calls >= 4096: + raise RuntimeError('Variant stdout call bound exceeded') + count = write0(1, raw[offset:offset + 65536]) + if type(count) is not int or count <= 0: + raise RuntimeError('Variant stdout made no progress') + offset += count + calls += 1 + except BaseException as error: + state[0] = error + state[2] = True + raise + + +# Accepted helper/control sources and parent-inspected native dependency tuple. +# These are static expected pins; finite and full execution gates remain closed. +EXPECTED_BOOTSTRAP_ROOT_SHA256 = 'f5a2d33f2b4d3651f214156a0e7094c2bb516ce2d5ab7698d18c11f98f35dee0' +NATIVE_TCB_HELPER_SHA256 = '865943df5cfdbf9383362d7fb2b76c6d0fd895cf0a0e20d550a26b579606b5d7' +NATIVE_TCB_CONTROLS_SHA256 = '63b1804caa7f89915662a1424f788c3becad13520e1f63212a338fb45aaa2c5a' +NATIVE_TCB_EXPECTED_FILES = (('/usr/bin/python3.12', 'e50d468e8b0adfb05733f5b87b3cff34829c4a8c1aea50c865aa8bdfe4bb150f', 8020928), + ('/usr/lib/python3.12/lib-dynload/_hashlib.cpython-312-x86_64-linux-gnu.so', + '8dc6cda6dd9495b95a2bfb5b26e8cf06b72f36dc0213d958b9277a958287f0fe', + 64368), + ('/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2', + 'c20a2dc8917c755f02b94049356320fe1f62ac7d9f8994731f807d9df39302da', + 236616), + ('/usr/lib/x86_64-linux-gnu/libc.so.6', + '3a15d66867d83762c7f2f1e37359cb8f6c5743edb369c65285cb0b1c4f7498bf', + 2129424), + ('/usr/lib/x86_64-linux-gnu/libcrypto.so.3', + '6866ed711dab8927e1bf82bf1cd30e828bdfc34f3cc1e83b1c9eb01ce6c37d9a', + 5309400), + ('/usr/lib/x86_64-linux-gnu/libexpat.so.1.9.1', + '286682ecbc5e59a638963b1a4e6351e65eb32fcf4bdcb9cb7569b6a61fe06a8d', + 186624), + ('/usr/lib/x86_64-linux-gnu/libm.so.6', + 'fce00b6f25f459cf4ae0b7fae4257909a1a8a86f9149e7c029a5d617baf1ccd0', + 952616), + ('/usr/lib/x86_64-linux-gnu/libz.so.1.3', + 'f61677c7bdb7c2aa2a243ea781bfd16afcb361cede7b4ef76127a9d8eb9a5242', + 113000)) +NATIVE_TCB_EXPECTED_HASHLIB_ORIGIN = '/usr/lib/python3.12/lib-dynload/_hashlib.cpython-312-x86_64-linux-gnu.so' + + +def _initial_native_tcb(): + root, api = _CAPTURED_BOOTSTRAP_ROOT, _CAPTURED_BOOTSTRAP_API + if (type(EXPECTED_BOOTSTRAP_ROOT_SHA256) is not str or + _INITIAL_ROOT_IDENTITY != EXPECTED_BOOTSTRAP_ROOT_SHA256 or + type(NATIVE_TCB_HELPER_SHA256) is not str or len(NATIVE_TCB_HELPER_SHA256) != 64 or + type(NATIVE_TCB_EXPECTED_FILES) is not tuple or + type(NATIVE_TCB_EXPECTED_HASHLIB_ORIGIN) is not str): + raise RuntimeError('Initial native TCB source and expected dependency tuple are not configured') + helper_path = __file__.rsplit('/', 2)[0] + '/areas/cache-validity/probe-native/native_tcb_v1.py' + api[0]() + digest, _, source = root._hash_regular(helper_path, 262144, True) + if digest != NATIVE_TCB_HELPER_SHA256: + raise RuntimeError('Initial native TCB helper source differs') + helper = root.ModuleType('_h25_initial_native_tcb') + namespace = helper.__dict__ + namespace.update({'__file__': helper_path, '__builtins__': root.builtins.__dict__}) + api[0]() + code = root._COMPILE(source, helper_path, 'exec', dont_inherit=True, optimize=root._OPTIMIZE) + api[0]() + root._EXEC(code, namespace) + api[0]() + receipt = namespace['verify_native_tcb'](root, api, NATIVE_TCB_EXPECTED_FILES, + NATIVE_TCB_EXPECTED_HASHLIB_ORIGIN) + if type(NATIVE_TCB_CONTROLS_SHA256) is not str or len(NATIVE_TCB_CONTROLS_SHA256) != 64: + raise RuntimeError('Initial native TCB control source pin is not configured') + control_path = __file__.rsplit('/', 2)[0] + '/areas/cache-validity/probe-native/native_tcb_controls_v1.py' + api[0]() + digest, _, control_source = root._hash_regular(control_path, 262144, True) + if digest != NATIVE_TCB_CONTROLS_SHA256: + raise RuntimeError('Initial native TCB controls source differs') + control_namespace = {'__name__': '_h25_initial_native_tcb_controls', '__file__': control_path, + '__builtins__': root.builtins.__dict__} + api[0]() + control_code = root._COMPILE(control_source, control_path, 'exec', dont_inherit=True, optimize=root._OPTIMIZE) + api[0]() + root._EXEC(control_code, control_namespace) + argv = root.sys.argv + if (type(argv) is not list or any(type(arg) is not str for arg in argv) or + argv.count('--output') != 1 or argv.index('--output') + 1 >= len(argv)): + raise RuntimeError('Early TCB controls require the unique parent --output argument') + output = argv[argv.index('--output') + 1] + stage_root = __file__.rsplit('/', 2)[0] + if (not output.startswith('/') or output.endswith('/') or + any(part in ('', '.', '..') for part in output.split('/')[1:]) or + output == stage_root or output.startswith(stage_root + '/')): + raise RuntimeError('Early TCB controls require a canonical absolute output outside the stage') + # Parent owns an existing nonsymlink output parent. mkdir is exclusive: + # a preexisting output, file, or symlink is rejected before any fixture write. + api[0]() + root.posix.mkdir(output, 0o700) + _vraw(output + '/initial-tcb.raw.json', receipt) + control_directory = output + '/initial-tcb-controls' + root.posix.mkdir(control_directory, 0o700) + api[0]() + controls = control_namespace['run_controls']( + helper, root, api, NATIVE_TCB_EXPECTED_FILES, NATIVE_TCB_EXPECTED_HASHLIB_ORIGIN, control_directory) + _vraw(output + '/initial-controls.raw.json', controls) + if (controls.get('schema') != 'h25-native-tcb-controls-v1' or + controls.get('expected_records') != 5 or len(controls.get('records', [])) != 5 or + controls.get('scientific_calls') != 0 or controls.get('probe_native_imports') != 0): + raise RuntimeError('Initial native TCB control census differs') + controls['status'] = 'NATIVE_INITIAL_TCB_CONTROLS_PASS' + api[0]() + restoration = namespace['verify_native_tcb']( + root, api, NATIVE_TCB_EXPECTED_FILES, NATIVE_TCB_EXPECTED_HASHLIB_ORIGIN) + _vraw(output + '/initial-restoration.raw.json', restoration) + if (type(restoration) is not dict or + restoration.get('status') != 'MATCHED_DECLARED_INITIAL_NATIVE_FILES' or + restoration.get('declared_file_count') != len(NATIVE_TCB_EXPECTED_FILES) or + restoration.get('probe_private_abi_access') is not False): + raise RuntimeError('Initial native TCB restoration corroboration differs') + return receipt, controls, output + + +# Child outer wall/CPU/RSS includes this entire initial trust check. +# It assumes the declared trusted OS/native startup; it does not prove itself. +try: + INITIAL_NATIVE_TCB_RECEIPT, INITIAL_NATIVE_TCB_CONTROLS, _INITIAL_OUTPUT = _initial_native_tcb() +except BaseException as _variant_bootstrap_error: + _VARIANT_TERMINAL_ERROR[0] = _variant_bootstrap_error + raise + +# This independent bootstrap support captures the initial system-stdlib +# continuity boundary before any adapter or scientific module is exposed. +# No late candidate-created snapshot is accepted as initial authentication. +COLD_AUTHORITY_SHA256 = '2a941111bdfd91037dfcbc5552aced004809240a7e2b43bfbce39fb35798af39' + + +def _initial_cold_authority(): + root, cap, api = (_CAPTURED_BOOTSTRAP_ROOT, _CAPTURED_BOOTSTRAP_CAPABILITY, + _CAPTURED_BOOTSTRAP_API) + if type(COLD_AUTHORITY_SHA256) is not str or len(COLD_AUTHORITY_SHA256) != 64: + raise RuntimeError('Initial cold authority source pin is not configured') + source_path = __file__.rsplit('/', 2)[0] + '/areas/cache-validity/cold_authority_v7.py' + api[0]() + digest, _, source = root._hash_regular(source_path, 1048576, True) + if digest != COLD_AUTHORITY_SHA256: + raise RuntimeError('Initial cold authority source differs') + module = root.ModuleType('_h25_initial_cold_authority') + namespace = module.__dict__ + namespace.update({'__file__': source_path, '__builtins__': root.builtins.__dict__}) + api[0]() + code = root._COMPILE(source, source_path, 'exec', dont_inherit=True, optimize=root._OPTIMIZE) + api[0]() + root._EXEC(code, namespace) + # The actual source bytes have just executed under the admitted initial + # interpreter/system-stdlib premise. Capture precedes every candidate import. + api[0]() + authority = namespace['capture_authority'](root, cap, api) + if (type(authority) is not tuple or len(authority) != 7 or + any(type(entry) is not root.FunctionType for entry in authority)): + raise RuntimeError('Initial cold authority must expose the sealed seven-entry tuple') + # Read fresh transport exactly once, before any candidate exposure. + transport = root.FunctionType.__dict__['__dict__'].__get__(authority[0], root.FunctionType) + descriptor = transport['_h25_caller_descriptor'] + if type(descriptor) is not tuple or len(descriptor) != 6 or descriptor[1] is not authority: + raise RuntimeError('Initial cold authority caller descriptor differs') + return authority, descriptor + + +import importlib +import typing +try: + _INITIAL_COLD_AUTHORITY, _INITIAL_COLD_CALLER_DESCRIPTOR = _initial_cold_authority() +except BaseException as _variant_bootstrap_error: + _VARIANT_TERMINAL_ERROR[0] = _variant_bootstrap_error + raise + +import time +START_WALL = time.perf_counter() +import argparse +from contextlib import redirect_stdout +from fractions import Fraction +import hashlib +import io +import json +import os +from pathlib import Path +import resource +import runpy +import shutil +import stat +import sys + +sys.dont_write_bytecode = True +# Independent source pins are literal final-stage configuration. These modules +# are admitted by the pre-exposure authority, including their live helper code. +# Driver/source identity does not depend on a hash of itself. +EARLY_INTEGRATION_SOURCE_PINS = ({'adapters': ('integration/adapters.py', 'f7ca7f4f03ac63c1a95ba42f06149543211566de5e29f487a3dc4d08c5ee9b94'), 'cold_build_evidence': ('integration/cold_build_evidence.py', 'aa0a315110e031e19291970c9611fe5e0f91465fa20eaec51e81186099563f78'), 'native_packet': ('integration/native_packet.py', '6adbcd1dfeb77fb6da7ee8f725796b1bfdbf0a4f397ef23f3a266a6b89d55892'), 'data_adapters': ('integration/data_adapters.py', 'c00c9c215d0b81a91dd5dffddacfd2225c4bc40fe3ba43c7b93677bb686591cc'), 'guarded_adapters_v4': ('integration/guarded_adapters_v4.py', '5579fe0838d8c6acf63834990269479c6c32024a1662846ed0a075c25d13954c'), '_h25_data_cache': ('areas/cache-validity/cache_contract_v8.py', '133c55e269b354542f86a2a1099f48cff052293d06da310f98b7cb33cb85258f')} + + + + + + +) +_INITIAL_INTEGRATION_MODULES = {} +_INITIAL_INTEGRATION_HANDLES = {} +for _entry_name, (_entry_relative, _entry_digest) in EARLY_INTEGRATION_SOURCE_PINS.items(): + if type(_entry_digest) is not str or len(_entry_digest) != 64: + raise RuntimeError('Early integration source pin is not configured: ' + _entry_name) + # BEGIN evaluated dispatch arguments scientific_driver:195 + _ca_args = (__file__.rsplit('/', 2)[0] + '/' + _entry_relative, _entry_digest, _entry_name) + _ca_kwargs = {} + # END evaluated dispatch arguments scientific_driver:195 + # BEGIN caller admission scientific_driver:195 + _ca_desc = _INITIAL_COLD_CALLER_DESCRIPTOR + _ca_p = _ca_desc[5] + _ca_type, _ca_function, _ca_id = _ca_p[0], _ca_p[1], _ca_p[2] + _ca_error, _ca_value_error, _ca_zip = _ca_p[7], _ca_p[8], _ca_p[18] + _ca_dispatch, _ca_record = _ca_desc[2], _ca_desc[3] + if _INITIAL_COLD_AUTHORITY is not _ca_desc[1] or _ca_dispatch is not _ca_record[0] or _ca_type(_ca_dispatch) is not _ca_function: + raise _ca_error('Cold authority caller dispatcher identity differs') + for (_ca_name, _ca_getter), _ca_expected in _ca_zip(_ca_p[4], _ca_record[1:7]): + if _ca_id(_ca_getter(_ca_dispatch, _ca_function)) != _ca_id(_ca_expected): + raise _ca_error('Cold authority caller dispatcher environment differs') + if _ca_record[4] is not None or _ca_record[5] is not None or _ca_record[7]: + raise _ca_error('Cold authority caller dispatcher defaults contract differs') + for _ca_cell, _ca_expected in _ca_record[8]: + try: + _ca_observed_id = _ca_id(_ca_p[6](_ca_cell, _ca_p[5])) + except _ca_value_error: + raise _ca_error('Cold authority caller dispatcher cell became empty') from None + if _ca_observed_id != _ca_id(_ca_expected): + raise _ca_error('Cold authority caller dispatcher cell differs') + # END caller admission scientific_driver:195 + _entry_module, _entry_handle = _ca_dispatch(0, *_ca_args, **_ca_kwargs) + if type(_entry_module) is not _CAPTURED_BOOTSTRAP_ROOT.ModuleType or sys.modules.get(_entry_name) is not _entry_module: + raise RuntimeError('Early integration module registry identity differs: ' + _entry_name) + _INITIAL_INTEGRATION_MODULES[_entry_name] = _entry_module + _INITIAL_INTEGRATION_HANDLES[_entry_name] = _entry_handle +adapters = _INITIAL_INTEGRATION_MODULES['adapters'] +native_packet = _INITIAL_INTEGRATION_MODULES['native_packet'] +data_adapters = _INITIAL_INTEGRATION_MODULES['data_adapters'] +guarded_adapters_v4 = _INITIAL_INTEGRATION_MODULES['guarded_adapters_v4'] + +# This is a build-only descendant of the original driver prefix. Never call +# native_packet.prepare, api[2], create_dynamic, exec_dynamic or a fixture loader. + +def _vdispatch(index, *args, **kwargs): + _ca_desc = _INITIAL_COLD_CALLER_DESCRIPTOR + _ca_p = _ca_desc[5] + _ca_type, _ca_function, _ca_id = _ca_p[0], _ca_p[1], _ca_p[2] + _ca_error, _ca_value_error, _ca_zip = _ca_p[7], _ca_p[8], _ca_p[18] + _ca_dispatch, _ca_record = _ca_desc[2], _ca_desc[3] + if _INITIAL_COLD_AUTHORITY is not _ca_desc[1] or _ca_dispatch is not _ca_record[0] or _ca_type(_ca_dispatch) is not _ca_function: + raise _ca_error('Cold authority caller dispatcher identity differs') + for (_ca_name, _ca_getter), _ca_expected in _ca_zip(_ca_p[4], _ca_record[1:7]): + if _ca_id(_ca_getter(_ca_dispatch, _ca_function)) != _ca_id(_ca_expected): + raise _ca_error('Cold authority caller dispatcher environment differs') + if _ca_record[4] is not None or _ca_record[5] is not None or _ca_record[7]: + raise _ca_error('Cold authority caller dispatcher defaults contract differs') + for _ca_cell, _ca_expected in _ca_record[8]: + try: + _ca_observed_id = _ca_id(_ca_p[6](_ca_cell, _ca_p[5])) + except _ca_value_error: + raise _ca_error('Cold authority caller dispatcher cell became empty') from None + if _ca_observed_id != _ca_id(_ca_expected): + raise _ca_error('Cold authority caller dispatcher cell differs') + return _ca_dispatch(index, *args, **kwargs) + + +def _vinvoke(name, export, *args): + # Current source identity is rechecked immediately before guarded invoke. + handle = _INITIAL_INTEGRATION_HANDLES[name] + _vdispatch(6, handle) + return _vdispatch(1, handle, export, *args) + + +def _vfile(path, bound): + raw, info = _vread(path, bound) + row = {'sha256': hashlib.sha256(raw).hexdigest(), 'bytes': len(raw), + 'mode': info.st_mode & 0o7777, + 'identity': {'device': info.st_dev, 'inode': info.st_ino, + 'mode': info.st_mode, 'links': info.st_nlink, 'uid': info.st_uid, + 'gid': info.st_gid, 'size': info.st_size, + 'mtime_ns': info.st_mtime_ns, 'ctime_ns': info.st_ctime_ns}} + return raw, row + + +def _vcustody(plan): + # All expected files are independently frozen source/header/compiler/link + # closure, including full system header/search/macro/specs witness inputs. + # This loop observes bytes; it cannot invent closure completeness. + rows, total = [], 0 + for entry in plan['source_files']: + raw, current = _vfile(entry['path'], 67108864) + total += len(raw) + if total > 268435456: + raise RuntimeError('Variant custody aggregate byte bound exceeded') + rows.append({'path': entry['path'], **current}) + return rows + + +def _vcheck_custody(observed, expected): + if (not _vsame(len(observed), len(expected))): + raise RuntimeError('Variant source inventory differs') + for row, fixed in zip(observed, expected): + if ((not _vsame(row['path'], fixed['path'])) or (not _vsame(row['sha256'], fixed['sha256'])) or + (not _vsame(row['bytes'], fixed['bytes'])) or (not _vsame(row['mode'], fixed['mode']))): + raise RuntimeError('Variant current source closure differs') + + +def _vroot(path): + counters = _CAPTURED_BOOTSTRAP_API[3](_CAPTURED_BOOTSTRAP_CAPABILITY) + _vraw(path, counters) + expected = ('load_calls', 'native_creations', 'native_execs', 'activation_attempts', + 'successful_bindings', 'deactivation_attempts', 'cleanup_failures', + 'control_module_creations') + if (type(counters) is not dict or (not _vsame(tuple(sorted(counters)), tuple(sorted(expected)))) or + any(type(counters[k]) is not int or (not _vsame(counters[k], 0)) for k in expected)): + raise RuntimeError('Build-only Root event counters differ') + return counters + + +_VARIANT_SOURCE_PINS = { + 'pyinit_failure': ('7656cd37503986459c4133643372fec13d3e5ad5553881f0bf0343a9a3e11abd', 17354), + 'exec_failure': ('f5066831bd812e7e88fb971ba0e7ca86dbef91fc40a1a68c17b040ce474cd880', 17040)} + + +def _vcheck_literal_sources(plan): + stage = __file__.rsplit('/', 2)[0] + if any(not 32 <= ord(c) < 127 for c in stage): + raise RuntimeError('Variant stage path alphabet differs') + rows = {row['path']: row for row in plan['source_files']} + if (not _vsame(len(rows), len(plan['source_files']))): + raise RuntimeError('Variant duplicate closure input') + for role in plan['roles']: + name = role['role'] + source_path = stage + '/areas/field-negative-variants-v1/' + name + '/dict_probe_fields_v1.c' + header_pin = _VARIANT_SOURCE_PINS[name] + expected = { + 'dict_probe_fields_v1.c': ('e0188999d41a9ab26e8d3d5c37b18b2238b3af21b1db90895f01f7be76d50b65', 17806), + 'field_service_v1.h': header_pin, + 'field_loader_snapshot_v1.h': ('bf7ab049cea89c0a882b279e35b1383ac8f99b66aa4b9b8e1ca22eb9c24c5a8d', 19495)} + if (not _vsame(role['source_path'], source_path)): + raise RuntimeError('Variant source role path differs') + for filename, (digest, size) in expected.items(): + row = role['source'] if filename.endswith('.c') else role['source_headers'][filename] + if (not _vsame(row, {'sha256': digest, 'bytes': size, 'mode': 292})): + raise RuntimeError('Variant reviewed source/header differs') + fixed = rows[source_path.rsplit('/', 1)[0] + '/' + filename] + if any((not _vsame(fixed[key], row[key])) for key in ('sha256', 'bytes', 'mode')): + raise RuntimeError('Variant role file omitted from closure') + if (not _vsame(plan['additional_source_pins'], [['sealed_elf_profile_v2', 'integration/sealed_elf_profile_v2.py', + '89ed8c777e6b72af2d6a3595037e7e92385924c6087d88010a27192633391016']])): + raise RuntimeError('Variant original ELF parser source pin differs') + if (not _vsame(plan['include'], '/usr/include/python3.12')): + raise RuntimeError('Variant original Python include differs') + + +def _variant_main(): + plan = _vplain(VARIANT_CONFIGURATION) + if ((not _vsame(len(plan['roles']), 2)) or + (not _vsame([row['role'] for row in plan['roles']], ['pyinit_failure', 'exec_failure'])) or + not 1 <= len(plan['source_files']) <= 512): + raise RuntimeError('Variant literal configuration differs') + output = _INITIAL_OUTPUT + if any(not 32 <= ord(c) < 127 for c in output): + raise RuntimeError('Variant output path alphabet differs') + argv = sys.argv[1:] + if ((not _vsame(len(argv), 6)) or (not _vsame(argv[0], '--output')) or (not _vsame(argv[2], '--generation')) or + (not _vsame(argv[4], '--launch-nonce')) or (not _vsame(argv[1], output)) or + not 1 <= len(argv[3]) <= 96 or (not _vsame(len(argv[5]), 64)) or + any(c not in 'abcdefghijklmnopqrstuvwxyz0123456789-' for c in argv[3]) or + any(c not in '0123456789abcdef' for c in argv[5])): + raise RuntimeError('Variant exact parent launch arguments differ') + binding = {'mode': 'optimized' if sys.flags.optimize else 'normal', + 'generation': argv[3], 'launch_nonce': argv[5]} + _vcheck_literal_sources(plan) + + for name, relative, digest in plan['additional_source_pins']: + module, handle = _vdispatch(0, __file__.rsplit('/', 2)[0] + '/' + relative, digest, name) + if type(module) is not _CAPTURED_BOOTSTRAP_ROOT.ModuleType or sys.modules.get(name) is not module: + raise RuntimeError('Variant additional module identity differs') + _INITIAL_INTEGRATION_MODULES[name] = module + _INITIAL_INTEGRATION_HANDLES[name] = handle + packet = {'bootstrap_root': _CAPTURED_BOOTSTRAP_ROOT, + 'bootstrap_capability': _CAPTURED_BOOTSTRAP_CAPABILITY, + 'bootstrap_api': _CAPTURED_BOOTSTRAP_API, 'late_started': False} + _vinvoke('native_packet', '_fresh', packet) + root_before = _vroot(output + '/root-before.raw.json') + preflight_before = _vinvoke('native_packet', '_preflight', packet) + _vraw(output + '/preflight-before.raw.json', preflight_before) + if (not _vsame(_vplain(preflight_before), plan['expected_preflight'])): + raise RuntimeError('Variant original preflight differs') + dependencies = _vinvoke('native_packet', '_dependencies') + # Dependencies preserved in custody raw, before comparing its original rows. + custody_before = _vcustody(plan) + _vraw(output + '/custody-before.raw.json', {'files': custody_before, 'original_dependencies': dependencies}) + _vcheck_custody(custody_before, plan['source_files']) + if (not _vsame(_vplain(dependencies), plan['expected_dependencies'])): + raise RuntimeError('Variant original compiler dependencies differ') + builds = [] + for index in (0, 1): + row = plan['roles'][index] + # Consume before mkdir/launch. Every exception stops this entire process; + # neither role can retry and the second cannot follow a first failure. + if _VARIANT_USED[index]: + raise RuntimeError('Variant build role already consumed') + _VARIANT_USED[index] = True + directory = output + '/' + row['role'] + _vops()[6](directory, 0o700) + target = directory + '/_h25_dict_probe.cpython-312-x86_64-linux-gnu.so' + command = ['/usr/bin/x86_64-linux-gnu-gcc-13', '-nostartfiles', '-shared', + '-fPIC', '-O3', '-std=c11', '-Wall', '-Wextra', '-Werror', + '-I' + plan['include'], row['source_path'], '-o', target] + context = {'source': row['source'], 'source_name': 'dict_probe_fields_v1.c', + 'no_cached_binary': True, 'module_name': '_h25_dict_probe', 'target': target, + 'source_headers': row['source_headers'], + 'system_header_admission_sha256': plan['system_header_admission_sha256'], + 'negative_variant_role': row['role']} + # Original unchanged cold_build_evidence.run through original authority. + # Its earlier internal failures are NOT covered by this outer handler. + _VARIANT_RETURNS[index] = _vinvoke('cold_build_evidence', 'run', + command, directory, 'control', 15, context) + _vraw(directory + '/helper-return.raw.json', _VARIANT_RETURNS[index]) + returned = _VARIANT_RETURNS[index] + if ((not _vsame(returned['returncode'], 0)) or returned['direct_child_reaped'] is not True or + (not _vsame(returned['status'], 'EXIT0_LOGS_STABLE_PENDING_SOURCE_CUSTODY'))): + raise RuntimeError('Variant cold helper did not complete successfully') + binary, binary_row = _vfile(target, 8388608) + build = {'schema': 'h25-negative-variant-build-v1', 'role': row['role'], + 'status': 'EXIT0_RAW_CAPTURED_PENDING_FINAL_CUSTODY', + 'helper_name': 'control', 'command': command, 'context': context, + 'path': target, 'binary': binary_row, + 'command_sha256': hashlib.sha256(_vencode({'argv': command})).hexdigest(), + 'original_helper_sha256': EARLY_INTEGRATION_SOURCE_PINS['cold_build_evidence'][1], + 'negative_only': True, 'loaded': False} + build_raw = _vencode(build) + _vwrite(directory + '/build.json', build_raw) + policy = dict(row['static_policy']) + if policy['build_receipt_sha256'] is not None: + raise RuntimeError('Variant actual receipt binding must not be prelearned') + policy['build_receipt_sha256'] = hashlib.sha256(build_raw).hexdigest() + # Tuple fields are source literals; conversion is structural, not a + # learned expectation. All other static policy fields stay independent. + for key in ('expected_exports', 'needed', 'required_local_functions', 'required_local_objects'): + policy[key] = tuple(policy[key]) + policy['pointer_slots'] = tuple(tuple(x) for x in policy['pointer_slots']) + policy['method_tables'] = tuple({'symbol': x['symbol'], 'entries': tuple(tuple(y) for y in x['entries'])} + for x in policy['method_tables']) + parsed = _vinvoke('sealed_elf_profile_v2', 'admit_service_elf', + binary, binary_row['sha256'], policy) + _vraw(directory + '/elf.raw.json', parsed) + # ELF parser already checks its static policy; no candidate image loads. + builds.append({'role': row['role'], 'build_receipt_sha256': hashlib.sha256(build_raw).hexdigest(), + 'output_sha256': binary_row['sha256'], 'elf_sha256': hashlib.sha256(_vencode(parsed)).hexdigest()}) + preflight_after = _vinvoke('native_packet', '_preflight', packet) + _vraw(output + '/preflight-after.raw.json', preflight_after) + dependencies_after = _vinvoke('native_packet', '_dependencies') + custody_after = _vcustody(plan) + _vraw(output + '/custody-after.raw.json', {'files': custody_after, 'original_dependencies': dependencies_after}) + _vcheck_custody(custody_after, plan['source_files']) + if ((not _vsame(_vplain(preflight_after), plan['expected_preflight'])) or + (not _vsame(_vplain(dependencies_after), plan['expected_dependencies'])) or + (not _vsame(custody_after, custody_before))): + raise RuntimeError('Variant final source/runtime custody differs') + root_after = _vroot(output + '/root-after.raw.json') + _vinvoke('native_packet', '_fresh', packet) + final = {'schema': 'h25-negative-variant-producer-v1', + 'status': 'TWO_BUILDS_RAW_AND_SOURCE_CAPTURED', 'producer_role': 'failure_variants', + 'binding': binding, + 'process_id': os.getpid(), 'builds': builds, + 'helper_names': ['control', 'control'], 'consumed_roles': list(_VARIANT_USED), + 'root_before': root_before, 'root_after': root_after, + 'negative_only': True, 'candidate_loads': 0, 'parent_completion': None, + 'domain_closed': None, 'failure_helper_qualification': None} + final_raw = _vencode(final) + _vwrite(output + '/receipt.json', final_raw) + _vstdout(final_raw) + + +# First bound outer failure remains rooted. No str/repr/annotation/secondary +# serialization occurs here; raw partial files remain for the owning parent. +try: + _variant_main() +except BaseException as _variant_error: + _VARIANT_TERMINAL_ERROR[0] = _variant_error + raise diff --git a/research/h25-c05-source-roots/snapshot/stages/combined-finite-v8/integration/cold_build_evidence.py.txt b/research/h25-c05-source-roots/snapshot/stages/combined-finite-v8/integration/cold_build_evidence.py.txt new file mode 100644 index 0000000000..9154e9300c --- /dev/null +++ b/research/h25-c05-source-roots/snapshot/stages/combined-finite-v8/integration/cold_build_evidence.py.txt @@ -0,0 +1,312 @@ +"""Retained evidence for only the three new native metadata compilations. + +The parent owns the outer process group, RSS guard and termination/join. Failure +snapshots are provisional while descendants can retain the raw-log descriptors. +No session or process group is created here. This module never runs on import. +""" +import hashlib +import json +import os +from pathlib import Path +import resource +import subprocess +import time +from types import BuiltinFunctionType, FunctionType + +OPERATIONAL_LOG_BYTES = 2 * 1024 * 1024 +CHILD_FILE_BYTES = 16 * 1024 * 1024 +READ_CHUNK_BYTES = 65536 +PREVIEW_BYTES = 512 +RECEIPT_BYTES = 65536 +POLL_SECONDS = 0.02 + + +class ColdBuildOutputLimit(RuntimeError): + pass + + +def _need(condition, message): + if not condition: + raise RuntimeError(message) + + +def _fingerprint(info): + return (info.st_dev, info.st_ino, info.st_mode, info.st_size, + info.st_mtime_ns, info.st_ctime_ns) + + +def _write_all(descriptor, raw): + offset = 0 + while offset < len(raw): + written = os.write(descriptor, raw[offset:]) + _need(written > 0, 'Cold build evidence write made no progress') + offset += written + + +def _encode(record): + raw = json.dumps(record, sort_keys=True, separators=(',', ':'), ensure_ascii=True).encode('ascii') + b'\n' + _need(len(raw) <= RECEIPT_BYTES, 'Cold build attempt receipt exceeded its declared bound') + return raw + + +def _record(journal_descriptor, attempt_path, record): + """Append intent first; atomic latest receipt cannot erase prior intent.""" + raw = _encode(record) + _write_all(journal_descriptor, raw) + os.fsync(journal_descriptor) + temporary = str(attempt_path) + '.pending' + descriptor = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_CLOEXEC | os.O_NOFOLLOW, 0o600) + try: + _write_all(descriptor, raw) + os.fsync(descriptor) + finally: + os.close(descriptor) + os.replace(temporary, attempt_path) + + +def _secondary_notice(error, phase, attempt_path): + """Bounded independent outer-stderr evidence when local evidence I/O fails.""" + try: + message = str(error) + record = {'schema': 'h25-cold-build-secondary-error-v1', 'phase': phase, + 'attempt_path': str(attempt_path), 'type': type(error).__name__, + 'message_prefix': message[:1024], 'message_truncated': len(message) > 1024} + _write_all(2, _encode(record)) + except BaseException: + # A broken outer stderr cannot be repaired inside this failed process. + pass + + +def _one_thread(): + """Bounded actual task census, not threading.enumerate or a remembered PASS.""" + tasks = [] + with os.scandir('/proc/self/task') as entries: + for entry in entries: + tasks.append(entry.name) + _need(len(tasks) <= 1, 'Cold build preexec requires exactly one live process task') + expected = str(os.getpid()) + _need(tasks == [expected], 'Cold build preexec task identity differs') + return {'process_id': os.getpid(), 'task_ids': [int(expected)], 'task_count': 1} + + +def _limit_callback(): + """Capture one builtin and immutable values; this changes the child only.""" + setter, getter = resource.setrlimit, resource.getrlimit + for entry, name in ((setter, 'setrlimit'), (getter, 'getrlimit')): + _need(type(entry) is BuiltinFunctionType and entry.__self__ is resource and entry.__name__ == name, + 'Cold build resource primitive owner differs') + resource_id = resource.RLIMIT_FSIZE + _need(type(resource_id) is int and resource_id == 1, 'Cold build Linux RLIMIT_FSIZE differs') + original = getter(resource_id) + _need(type(original) is tuple and len(original) == 2 and + all(type(value) is int and (value == resource.RLIM_INFINITY or value >= CHILD_FILE_BYTES) + for value in original), 'Existing file limit is below the declared child cap') + limits = (CHILD_FILE_BYTES, CHILD_FILE_BYTES) + + def apply_child_limit(): + setter(resource_id, limits) + + captured = (apply_child_limit.__code__, apply_child_limit.__defaults__, + apply_child_limit.__kwdefaults__, + tuple(cell.cell_contents for cell in apply_child_limit.__closure__)) + _need(apply_child_limit.__code__.co_names == () and + apply_child_limit.__code__.co_freevars == ('limits', 'resource_id', 'setter'), + 'Cold build preexec closure unexpectedly reads globals') + return apply_child_limit, captured, original + + +def _check_limit_callback(callback, captured): + _need(type(callback) is FunctionType and callback.__code__ is captured[0] and + callback.__defaults__ is captured[1] is None and callback.__kwdefaults__ is captured[2] is None and + len(callback.__closure__) == len(captured[3]) and + all(cell.cell_contents is expected for cell, expected in zip(callback.__closure__, captured[3])), + 'Cold build preexec closure changed before fork') + limits, resource_id, setter = captured[3] + _need(type(limits) is tuple and limits == (CHILD_FILE_BYTES, CHILD_FILE_BYTES) and + type(resource_id) is int and resource_id == resource.RLIMIT_FSIZE == 1 and + type(setter) is BuiltinFunctionType and setter is resource.setrlimit and + setter.__self__ is resource and setter.__name__ == 'setrlimit', + 'Cold build captured native resource setter changed') + + +def _snapshot(path, writer_descriptor, *, success): + """At most 2 MiB hashed and 512 bytes previewed, even for a failed writer.""" + descriptor = os.open(path, os.O_RDONLY | os.O_CLOEXEC | os.O_NOFOLLOW) + try: + before = os.fstat(descriptor) + writer = os.fstat(writer_descriptor) + _need((before.st_dev, before.st_ino) == (writer.st_dev, writer.st_ino) and + (before.st_mode & 0o170000) == 0o100000, 'Cold build raw log ownership differs') + remaining = min(before.st_size, OPERATIONAL_LOG_BYTES) + digest, count, preview = hashlib.sha256(), 0, b'' + while remaining: + block = os.read(descriptor, min(READ_CHUNK_BYTES, remaining)) + if not block: + break + digest.update(block) + count += len(block) + remaining -= len(block) + if len(preview) < PREVIEW_BYTES: + preview += block[:PREVIEW_BYTES - len(preview)] + after = os.fstat(descriptor) + stable = _fingerprint(before) == _fingerprint(after) + if success: + _need(before.st_size <= OPERATIONAL_LOG_BYTES and stable and count == before.st_size, + 'Completed compiler log is oversized, short or changed while hashed') + return {'path': str(path), 'bytes_before': before.st_size, 'bytes_after': after.st_size, + 'prefix_bytes_hashed': count, 'prefix_sha256': digest.hexdigest(), + 'preview_bytes': len(preview), 'preview_utf8': preview.decode('utf-8', errors='replace'), + 'stable_during_snapshot': stable, + 'complete_file_sha256': digest.hexdigest() if success else None, + 'raw_finality': ('DIRECT_CHILD_EXIT0_AND_STABLE_COMPLETED_LOG' if success else + 'PROVISIONAL_UNTIL_OUTER_PROCESS_GROUP_TERMINATED_AND_JOINED'), + 'operational_threshold_bytes': OPERATIONAL_LOG_BYTES, + 'child_inherited_hard_file_limit_bytes': CHILD_FILE_BYTES} + finally: + os.close(descriptor) + + +def run(command, directory, name, timeout_seconds, context): + """Run a single pinned compiler or separately approved bounded toy command. + + Failure never kills or declares descendants joined. It records available raw + prefixes and raises the original exception for the outer guard to terminate + and join the complete existing process group. Native compilation sources and + binary custody are checked independently by native_packet.prepare. + """ + _need(type(command) is list and 1 <= len(command) <= 64 and + all(type(value) is str and len(value) <= 8192 for value in command) and + command[0].startswith('/'), 'Cold build command must be bounded with absolute executable') + _need(type(timeout_seconds) in (int, float) and 0 < timeout_seconds <= 15, + 'Cold build timeout is outside its declared bound') + _need(type(name) is str and name in ('production', 'watcher', 'bounds', 'control'), + 'Cold build evidence name differs') + directory = Path(directory) + _need(directory.is_absolute() and directory.is_dir() and not directory.is_symlink(), + 'Cold build evidence directory must be existing absolute regular directory') + stdout_path, stderr_path = directory / (name + '.stdout.raw'), directory / (name + '.stderr.raw') + attempt_path, journal_path = directory / (name + '.attempt.json'), directory / (name + '.attempt.jsonl') + flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_CLOEXEC | os.O_NOFOLLOW + journal = os.open(journal_path, flags, 0o600) + stdout = stderr = None + process = None + phase, spawn_entered, spawn_returned = 'prelaunch', False, False + primary_in_flight = False + record = {'schema': 'h25-cold-build-attempt-v1', 'status': 'PRELAUNCH_INTENT', + 'command': list(command), 'timeout_seconds': timeout_seconds, 'context': context, + 'stdout_path': str(stdout_path), 'stderr_path': str(stderr_path), + 'attempt_path': str(attempt_path), 'journal_path': str(journal_path), + 'process_group_policy': 'INHERIT_OUTER_GROUP_NO_NEW_SESSION', + 'operational_log_threshold_bytes': OPERATIONAL_LOG_BYTES, + 'child_only_inherited_hard_file_limit_bytes': CHILD_FILE_BYTES, + 'returncode': None, 'process_id': None, 'direct_child_reaped': None, + 'spawn_entered': False, 'spawn_returned': False, + 'descendant_termination_joined': False, + 'failure_log_hashes_final': False} + try: + # Files and durable intent exist before any subprocess operation. + stdout = os.open(stdout_path, flags, 0o600) + stderr = os.open(stderr_path, flags, 0o600) + _record(journal, attempt_path, record) + callback, captured, original_limits = _limit_callback() + record['parent_file_limits_before'] = list(original_limits) + record['preexec_code_sha256'] = hashlib.sha256(callback.__code__.co_code).hexdigest() + _check_limit_callback(callback, captured) + record['single_thread_before_spawn'] = _one_thread() + # No callbacks, imports, thread starts or mutable configuration operations + # occur between this actual census/closure check and the subprocess call. + phase, spawn_entered = 'spawn', True + started = time.monotonic() + process = subprocess.Popen(command, stdin=subprocess.DEVNULL, stdout=stdout, stderr=stderr, + close_fds=True, start_new_session=False, preexec_fn=callback) + spawn_returned = True + record.update(status='STARTED', process_id=process.pid, spawn_entered=True, spawn_returned=True) + _record(journal, attempt_path, record) + phase = 'wait' + while True: + code = process.poll() + sizes = (os.fstat(stdout).st_size, os.fstat(stderr).st_size) + if max(sizes) > OPERATIONAL_LOG_BYTES: + raise ColdBuildOutputLimit('Compiler raw log exceeded the 2 MiB operational threshold') + if code is not None: + code = process.wait() # actual completed wait, never an invented returncode + record.update(returncode=code, direct_child_reaped=True) + break + remaining = timeout_seconds - (time.monotonic() - started) + if remaining <= 0: + raise subprocess.TimeoutExpired(command, timeout_seconds) + time.sleep(min(POLL_SECONDS, remaining)) + if code != 0: + raise subprocess.CalledProcessError(code, command) + phase = 'success_log_snapshot' + os.fsync(stdout) + os.fsync(stderr) + logs = {'stdout': _snapshot(stdout_path, stdout, success=True), + 'stderr': _snapshot(stderr_path, stderr, success=True)} + _need(resource.getrlimit(resource.RLIMIT_FSIZE) == original_limits, + 'Compiler child limit changed the parent process limits') + record.update(status='EXIT0_LOGS_STABLE_PENDING_SOURCE_CUSTODY', logs=logs, + parent_file_limits_after=list(resource.getrlimit(resource.RLIMIT_FSIZE)), + failure_log_hashes_final=False) + _record(journal, attempt_path, record) + return record + except BaseException as primary_error: + primary_in_flight = True + # Metadata is secondary; it must never erase or replace a launch/wait error. + try: + code = None if process is None else process.poll() + record.update(status=('TIMEOUT' if isinstance(primary_error, subprocess.TimeoutExpired) else + 'NONZERO_EXIT' if isinstance(primary_error, subprocess.CalledProcessError) else + 'LOG_LIMIT' if isinstance(primary_error, ColdBuildOutputLimit) else + 'STARTUP_FAILURE' if phase == 'spawn' else + 'PRELAUNCH_REJECTION' if phase == 'prelaunch' else 'EVIDENCE_FAILURE'), + failure_phase=phase, spawn_entered=spawn_entered, spawn_returned=spawn_returned, + returncode=code, direct_child_reaped=(code is not None if process is not None else None), + error={'type': type(primary_error).__name__, 'message': str(primary_error)}, + timeout_output_policy='RAW_FILES_RETAINED_NO_PIPE_CAPTURE', + descendant_termination_joined=False, failure_log_hashes_final=False) + logs = {} + for key, path, descriptor in (('stdout', stdout_path, stdout), ('stderr', stderr_path, stderr)): + if descriptor is not None: + try: + logs[key] = _snapshot(path, descriptor, success=False) + except BaseException as snapshot_error: + logs[key] = {'path': str(path), 'complete_file_sha256': None, + 'raw_finality': 'PROVISIONAL_UNTIL_OUTER_PROCESS_GROUP_TERMINATED_AND_JOINED', + 'snapshot_error': {'type': type(snapshot_error).__name__, + 'message': str(snapshot_error)}} + record['logs'] = logs + _record(journal, attempt_path, record) + except BaseException as evidence_error: + # PRELAUNCH_INTENT/STARTED journal and raw files remain independent. + _secondary_notice(evidence_error, 'failure-evidence', attempt_path) + raise + finally: + close_errors = [] + for descriptor in (stdout, stderr): + if descriptor is not None: + try: + os.close(descriptor) + except OSError as close_error: + close_errors.append(close_error) + _secondary_notice(close_error, 'raw-log-parent-close', attempt_path) + if close_errors: + try: + record.update(prior_status=record.get('status'), status='EVIDENCE_FAILURE', + failure_phase='raw-log-parent-close', + close_errors=[{'type': type(error).__name__, 'message': str(error)} + for error in close_errors], + failure_log_hashes_final=False) + for row in record.get('logs', {}).values(): + row['complete_file_sha256'] = None + row['raw_finality'] = 'PROVISIONAL_UNTIL_OUTER_PROCESS_GROUP_TERMINATED_AND_JOINED' + _record(journal, attempt_path, record) + except BaseException as evidence_error: + _secondary_notice(evidence_error, 'close-evidence', attempt_path) + try: + os.close(journal) + except OSError as close_error: + close_errors.append(close_error) + _secondary_notice(close_error, 'journal-parent-close', attempt_path) + if close_errors and not primary_in_flight: + raise close_errors[0] diff --git a/research/h25-c05-source-roots/source_roots_v1.py b/research/h25-c05-source-roots/source_roots_v1.py new file mode 100644 index 0000000000..7f014535ae --- /dev/null +++ b/research/h25-c05-source-roots/source_roots_v1.py @@ -0,0 +1,123 @@ +"""Pure C05 enabling construction. Never a complete C05 inventory or launcher.""" +import hashlib + +CONFIGURATION = SOURCE_REVIEW = EXECUTION = None +ROLES = ('pyinit_failure', 'exec_failure') +C = 'dict_probe_fields_v1.c' +L = 'field_loader_snapshot_v1.h' +H = 'field_service_v1.h' +COMMON = { + C: ('e0188999d41a9ab26e8d3d5c37b18b2238b3af21b1db90895f01f7be76d50b65', 17806), + L: ('bf7ab049cea89c0a882b279e35b1383ac8f99b66aa4b9b8e1ca22eb9c24c5a8d', 19495), +} +SERVICE = { + 'pyinit_failure': ('7656cd37503986459c4133643372fec13d3e5ad5553881f0bf0343a9a3e11abd', 17354), + 'exec_failure': ('f5066831bd812e7e88fb971ba0e7ca86dbef91fc40a1a68c17b040ce474cd880', 17040), +} +# Whole-source authentication makes this a fixed-source extraction, not a C parser. +SITES = { + C: ((11, ''), (12, '"internal/pycore_dict.h"'), + (13, ''), (14, ''), (15, ''), + (422, '"field_loader_snapshot_v1.h"'), (456, '"field_service_v1.h"')), + L: ((13, ''), (14, ''), (15, '')), + H: (), +} + +class ConstructionOpen(RuntimeError): + pass + +def require(ok, message): + if not ok: + raise ConstructionOpen(message) + +def absolute(path): + require(type(path) is str and 1 < len(path) <= 4096, + 'bounded exact path required') + require(path.startswith('/') and all(32 <= ord(c) < 127 for c in path) + and all(p not in ('', '.', '..') for p in path.split('/')[1:]), + 'canonical absolute path required') + return path + +def source_roots(payloads, stage, output, mode): + """Six (role, filename) keys map to inert original source bytes. + + Site order is deterministic serialization, not preprocessing event order. + Mode is supplied binding data; 292 is required installation mode, not stat. + """ + absolute(stage) + absolute(output) + require(type(mode) is str and mode in ('normal', 'optimized'), 'mode differs') + require(output != stage and not output.startswith(stage + '/'), 'output inside stage') + require(type(payloads) is dict and len(payloads) == 6, 'six exact payload entries required') + for key in payloads: + require(type(key) is tuple and len(key) == 2 and + all(type(x) is str for x in key), 'foreign payload key') + expected_keys = {(role, name) for role in ROLES for name in (C, L, H)} + require(set(payloads) == expected_keys, 'six source occurrences required') + files, sites, commands = [], [], [] + for role in ROLES: + directory = stage + '/areas/field-negative-variants-v1/' + role + pins = dict(COMMON, **{H: SERVICE[role]}) + for name in (C, L, H): + raw = payloads[(role, name)] + digest, size = pins[name] + require(type(raw) is bytes and len(raw) == size, 'source length differs') + require(hashlib.sha256(raw).hexdigest() == digest, 'source digest differs') + path = absolute(directory + '/' + name) + files.append({'path': path, 'sha256': digest, 'bytes': size, 'mode': 292}) + lines = raw.decode('ascii').splitlines() + for line, operand in SITES[name]: + require(lines[line - 1] == '#include ' + operand, 'source site differs') + sites.append((role, path, line, operand)) + target = absolute(output + '/' + role + '/_h25_dict_probe.cpython-312-x86_64-linux-gnu.so') + require(target != stage and not target.startswith(stage + '/'), 'target inside stage') + commands.append((role, [ + '/usr/bin/x86_64-linux-gnu-gcc-13', '-nostartfiles', '-shared', + '-fPIC', '-O3', '-std=c11', '-Wall', '-Wextra', '-Werror', + '-I/usr/include/python3.12', directory + '/' + C, '-o', + target])) + return {'mode': mode, 'commands': tuple(commands), 'project_files': files, + 'literal_include_obligations': tuple(sites), + 'full_c05': False, 'runtime_qualified': False} + +def no_pch_prefix(name, effective_chain, facts): + """Conditional ordinary-header subcase; facts are inert observer DATA. + + The caller must separately prove effective_chain, namespace authenticity, + stability, compatible cache state, inactive remapping/custom construction, and normalized MISSING + semantics. This function establishes none of those premises. + A present PCH, symlink, unsupported object or read error leaves the subcase OPEN. + """ + require(type(name) is str and 0 < len(name) <= 8192 and not name.startswith('/') + and all(p not in ('', '.', '..') for p in name.split('/')), 'include name differs') + require(type(effective_chain) is tuple and 0 < len(effective_chain) <= 512, + 'bounded effective chain required') + require(type(facts) is dict and len(facts) <= 4096, 'bounded fact mapping required') + for directory in effective_chain: + absolute(absolute(directory) + '/' + name + '.gch') + total = 0 + for key, value in facts.items(): + require(type(key) is str and type(value) is tuple and len(value) == 2, + 'foreign lookup fact') + require(type(value[0]) is str and type(value[1]) is bytes, 'foreign lookup value') + absolute(key) + require(value[0] in ('MISSING', 'REGULAR') and len(value[1]) <= 67108864, + 'unsupported lookup disposition') + require(value[0] != 'MISSING' or value[1] == b'', 'missing fact carries bytes') + total += len(value[1]) + require(total <= 268435456, 'fact byte bound exceeded') + events = [] + for directory in effective_chain: + path = absolute(absolute(directory) + '/' + name) + # Conservative no-PCH subcase. This does not claim GCC probes a PCH + # at every site, nor reject a legal compiler configuration globally. + for candidate, is_pch in ((absolute(path + '.gch'), True), (path, False)): + require(candidate in facts, 'missing independent lookup observation') + disposition, raw = facts[candidate] + if disposition == 'MISSING': + events.append((candidate, 'MISSING')) + continue + require(not is_pch, 'present PCH requires additional source rules') + events.append((candidate, 'REGULAR', hashlib.sha256(raw).hexdigest(), len(raw))) + return tuple(events), candidate + raise ConstructionOpen('no ordinary header resolved')