CodeSampleX

サンプル

cffi 2.1.1: FFI.string, FFI.unpack, FFI.buffer

検証済みサンプル — pypi cffi 2.1.1: FFI.string, FFI.unpack, FFI.buffer. python 3.12 · linux debian/x64 · docker で contract を実行し、成功しました.

sha256:02f4c1f7cf3cf7ad29a769af7907902836f81272e9a2db3e07e64409cc27c380

このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。 合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。 MIT-0

実行証拠

宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。

証拠の基準
署名済みコントラクト合格
検証レシート
1
ビルドした署名鍵
1
宣言された環境 python linux 24 · ubuntu · glibc 2.39 x64 python python pip

検証実行環境

環境 コントラクト ステージ 実行日
python 3.12 · linux debian/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1python:3.12-slim@sha256:09f7da3bc104…
2026-09-19

ケース

HOW
ゴール
verify pkg:pypi/cffi@2.1.1
パッケージ
シンボル
  • cffi.FFI.string
  • cffi.FFI.unpack
  • cffi.FFI.buffer
  • cffi.FFI.new
環境
python
作成日
2026-09-18T17:26:04Z

コントラクト

  1. Calling ffi.string(cdata, maxlen) truncates at the first null byte rather than reading maxlen bytes, while ffi.unpack extracts the exact byte count across embedded nulls.
  2. ffi.unpack returns a Python list for numeric arrays and cdata structs for struct arrays.
  3. ffi.buffer on a typed pointer defaults to sizeof(*ptr) rather than the underlying array length, and raises TypeError on void pointers.
  4. Writing to an ffi.buffer slice mutates the underlying C struct memory in-place.
  5. ffi.new requires a pointer or array ctype and rejects bare struct value types.
  6. Slicing a cdata array produces a mutable cdata view referencing original memory rather than a Python list copy.
  7. ffi.string on wchar_t arrays returns str rather than bytes, while ffi.unpack returns str preserving embedded nulls.

ファイル

  • NOTES.md
  • PROMPT.md
  • csx.json
  • requirements.txt
  • spec.json
  • test/contract.py

ソースアーティファクトをダウンロード (tar.gz)

ソース

NOTES.md
# CFFI Data Marshalling and Buffer Contracts

## Known Solution Search
A lookup via `search_known_solution` for `pkg:pypi/cffi@2.1.1` indicated that verified contract coverage is needed for cffi 2.1.1 in python/linux.

## Pinned Release
- Package: `cffi` 2.1.1
- Dependency: `pycparser` 3.0
- Environment: Python 3.12 / Linux x86_64

## Observed Behaviors and Failure Modes

### 1. `ffi.string` vs `ffi.unpack` with Embedded Null Bytes
- **Trap**: When reading binary data from a C buffer (such as serialized structs or binary payloads), callers might expect `ffi.string(ptr, maxlen)` to read `maxlen` bytes.
- **Observed Behavior**: `ffi.string(cdata, maxlen)` scans for a null byte (`\0`) and terminates immediately upon finding one, returning only the prefix before the null byte even if `maxlen` is much larger.
- **Failure Mode**: Silent truncation of binary payload containing null bytes.
- **Remedy**: `ffi.unpack(ptr, length)` must be used when reading binary payloads of known length, preserving embedded null bytes.

### 2. Return Types of `ffi.unpack`
- For `char *` or `char[]`, `ffi.unpack` returns a Python `bytes` object.
- For primitive numeric arrays (`int *`, `double *`), `ffi.unpack` returns a Python `list` of numbers.
- For struct arrays, `ffi.unpack` returns a Python `list` of `cdata` struct instances.
- For `wchar_t *`, `ffi.unpack` returns a Python unicode `str`.

### 3. `ffi.buffer` Default Size on Pointers vs Arrays
- **Trap**: Calling `ffi.buffer(ptr)` on a pointer allocated from an array might be expected to cover the entire underlying allocation.
- **Observed Behavior**: For fixed-size array declarations (`Node[2]`), `len(ffi.buffer(arr))` defaults to `sizeof(Node[2])`. For typed pointer declarations (`Node *`), `len(ffi.buffer(ptr))` defaults to `sizeof(Node)` (1 item).
- **Failure Mode**: For `void *` pointers, calling `ffi.buffer(void_ptr)` raises `TypeError`.
- **Mutation**: Writing to an `ffi.buffer` slice directly performs in-place zero-copy mutation on the underlying C memory.

### 4. `ffi.new` Type Requirements
- **Trap**: Attempting to instantiate a struct value via `ffi.new("Point")`.
- **Observed Behavior**: `ffi.new` requires pointer (`Point *`) or array (`Point[]`) ctype declarations. Passing a bare struct type raises `TypeError`.

### 5. `cdata` Array Slicing Semantics
- Slicing a `cdata` array (`arr[start:end]`) returns a live `cdata` slice view referencing the backing memory rather than a detached Python list copy. Mutating `slice_view[0]` mutates `arr[start]` in-place.
PROMPT.md
Clean-room public code sample — generation instructions

Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.

A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.

Goal: verify pkg:pypi/cffi@2.1.1
Kind: HOW

Use EXACTLY these public packages and versions:
  - pkg:pypi/cffi@2.1.1

Rules:
  - One focused purpose; the smallest project that proves the goal.
  - Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
  - Pin every dependency with a lockfile so resolution is reproducible.
  - No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
  - No personal names, emails, company names, or project identifiers of any kind.
  - No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
  - Keep it under 200 files and 256KB packed.
csx.json
{"case":{"believed":"Calling ffi.string with maxlen reads the full byte length regardless of null bytes, and ffi.buffer on a pointer defaults to the full allocated buffer length.","caseId":"case:sha256:101163e28758d7b121adfe3e5dfee0b06aa55339a58a09545959c57d19be2e7a","contract":["Calling ffi.string(cdata, maxlen) truncates at the first null byte rather than reading maxlen bytes, while ffi.unpack extracts the exact byte count across embedded nulls.","ffi.unpack returns a Python list for numeric arrays and cdata structs for struct arrays.","ffi.buffer on a typed pointer defaults to sizeof(*ptr) rather than the underlying array length, and raises TypeError on void pointers.","Writing to an ffi.buffer slice mutates the underlying C struct memory in-place.","ffi.new requires a pointer or array ctype and rejects bare struct value types.","Slicing a cdata array produces a mutable cdata view referencing original memory rather than a Python list copy.","ffi.string on wchar_t arrays returns str rather than bytes, while ffi.unpack returns str preserving embedded nulls."],"goal":"verify pkg:pypi/cffi@2.1.1","kind":"HOW","packages":["pkg:pypi/cffi@2.1.1"],"schemaVersion":1,"symbols":["cffi.FFI.string","cffi.FFI.unpack","cffi.FFI.buffer","cffi.FFI.new"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"pypi","executionContext":"python","language":"python","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/cffi@2.1.1"],"schemaVersion":1,"subject":"pkg:pypi/cffi@2.1.1","symbols":["cffi.FFI.string","cffi.FFI.unpack","cffi.FFI.buffer","cffi.FFI.new"],"verifierAdapter":"python@1"}
requirements.txt
cffi==2.1.1
pycparser==3.0
spec.json
{
  "schemaVersion": 1,
  "goal": "verify pkg:pypi/cffi@2.1.1",
  "kind": "HOW",
  "packages": [
    "pkg:pypi/cffi@2.1.1"
  ]
}
test/contract.py
import cffi
import struct


def test_cffi_contract():
    ffi = cffi.FFI()

    ffi.cdef("""
        typedef struct {
            int x;
            int y;
        } Point;

        typedef struct {
            int id;
            Point origin;
            char tag[8];
        } Node;
    """)

    # Contract 1: ffi.string truncates at first null byte regardless of maxlen
    raw_payload = b"header\x00body\x00tail"
    char_array = ffi.new("char[]", raw_payload)

    str_truncated = ffi.string(char_array, len(raw_payload))
    assert str_truncated == b"header", f"Expected b'header', got {str_truncated!r}"
    assert len(str_truncated) == 6

    unpacked_raw = ffi.unpack(char_array, 11)
    assert unpacked_raw == b"header\x00body", f"Expected b'header\\x00body', got {unpacked_raw!r}"
    assert isinstance(unpacked_raw, bytes)
    assert len(unpacked_raw) == 11

    # Contract 2: ffi.unpack returns Python lists for numeric & struct arrays
    int_array = ffi.new("int[]", [10, 20, 30, 40])
    unpacked_ints = ffi.unpack(int_array, 4)
    assert isinstance(unpacked_ints, list)
    assert unpacked_ints == [10, 20, 30, 40]

    nodes = ffi.new("Node[2]", [
        {"id": 1, "origin": {"x": 10, "y": 20}, "tag": b"node1"},
        {"id": 2, "origin": {"x": 30, "y": 40}, "tag": b"node2"}
    ])
    unpacked_nodes = ffi.unpack(nodes, 2)
    assert isinstance(unpacked_nodes, list)
    assert len(unpacked_nodes) == 2
    assert unpacked_nodes[0].id == 1 and unpacked_nodes[0].origin.x == 10
    assert unpacked_nodes[1].id == 2 and unpacked_nodes[1].origin.y == 40

    # Contract 3: ffi.buffer default sizing on arrays vs typed pointers vs void*
    buf_array = ffi.buffer(nodes)
    assert len(buf_array) == ffi.sizeof("Node[2]")

    nodes_ptr = ffi.cast("Node *", nodes)
    buf_ptr = ffi.buffer(nodes_ptr)
    assert len(buf_ptr) == ffi.sizeof("Node")
    assert len(buf_ptr) != len(buf_array)

    void_ptr = ffi.cast("void *", nodes)
    try:
        ffi.buffer(void_ptr)
        assert False, "ffi.buffer(void *) without size should raise TypeError"
    except TypeError as e:
        assert "void *" in str(e)

    # Contract 4: in-place zero-copy mutation via ffi.buffer
    explicit_buf = ffi.buffer(nodes, ffi.sizeof("Node[2]"))
    assert len(explicit_buf) == ffi.sizeof("Node[2]")
    offset_node2_x = ffi.sizeof("Node") + ffi.offsetof("Node", "origin") + ffi.offsetof("Point", "x")
    explicit_buf[offset_node2_x:offset_node2_x + 4] = struct.pack("i", 999)
    assert nodes[1].origin.x == 999

    # Contract 5: ffi.new requires pointer or array ctype, rejects value types
    try:
        ffi.new("Point")
        assert False, "ffi.new('Point') should raise TypeError"
    except TypeError as e:
        assert "pointer or array ctype" in str(e)

    # Contract 6: cdata array slicing produces a mutable cdata view, not a list copy
    numbers = ffi.new("int[]", [100, 200, 300, 400, 500])
    slice_view = numbers[1:4]
    assert ffi.typeof(slice_view).kind == "array"
    assert len(slice_view) == 3
    slice_view[0] = 777
    assert numbers[1] == 777

    # Contract 7: wchar_t string conversion vs unpack
    wc = ffi.new("wchar_t[]", "alpha\x00beta")
    wc_str = ffi.string(wc)
    assert wc_str == "alpha"
    assert isinstance(wc_str, str)
    wc_unpacked = ffi.unpack(wc, 10)
    assert wc_unpacked == "alpha\x00beta"
    assert isinstance(wc_unpacked, str)


if __name__ == "__main__":
    test_cffi_contract()
    print("cffi contract passed successfully.")

オリジンシーダー

匿名