112 lines
3.9 KiB
Python
112 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Compile the exact picklebuf_raw body as C89 and check its error order."""
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
source = Path(sys.argv[1]).read_text()
|
|
match = re.search(
|
|
r"static PyObject \*\npicklebuf_raw\([^\n]+\)\n\{.*?\n\}", source, re.S
|
|
)
|
|
assert match, "picklebuf_raw not found"
|
|
harness = r'''
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
typedef struct { int unused; } PyObject;
|
|
typedef struct {
|
|
PyObject *obj;
|
|
long *suboffsets;
|
|
const char *format;
|
|
int ndim;
|
|
long itemsize, len;
|
|
long *shape, *strides;
|
|
} Py_buffer;
|
|
typedef struct { Py_buffer view; } PyPickleBufferObject;
|
|
typedef struct { Py_buffer view; int flags; } PyMemoryViewObject;
|
|
#define Py_UNUSED(name) name
|
|
#define _Py_MEMORYVIEW_C 1
|
|
#define _Py_MEMORYVIEW_FORTRAN 2
|
|
static int PyExc_ValueError = 1, PyExc_BufferError = 2;
|
|
static int scenario;
|
|
static char events[16];
|
|
static PyPickleBufferObject self;
|
|
static PyMemoryViewObject memory;
|
|
static PyObject base;
|
|
static void event(char c) {
|
|
size_t n = strlen(events);
|
|
assert(n + 1 < sizeof(events));
|
|
events[n] = c; events[n + 1] = '\0';
|
|
}
|
|
static void PyErr_SetString(int exc, const char *message) {
|
|
assert(exc == (scenario == 0 ? PyExc_ValueError : PyExc_BufferError));
|
|
assert(strcmp(message, scenario == 0
|
|
? "operation forbidden on released PickleBuffer object"
|
|
: "cannot extract raw buffer from non-contiguous buffer") == 0);
|
|
event('E');
|
|
}
|
|
static int PyBuffer_IsContiguous(Py_buffer *view, char order) {
|
|
assert(view == &self.view && order == 'A'); event('C');
|
|
return scenario != 2;
|
|
}
|
|
static PyObject *PyMemoryView_FromObject(PyObject *obj) {
|
|
assert(obj == (PyObject *)&self); event('M');
|
|
return scenario == 3 ? NULL : (PyObject *)&memory;
|
|
}
|
|
'''
|
|
harness += match.group(0)
|
|
harness += r'''
|
|
int main(void) {
|
|
static const char *expected[] = {"E", "E", "CE", "CM", "CM"};
|
|
PyObject *result;
|
|
PyMemoryViewObject before;
|
|
Py_buffer original;
|
|
long offset = 0;
|
|
for (scenario = 0; scenario < 5; ++scenario) {
|
|
memset(&memory, 0, sizeof(memory));
|
|
memory.view.obj = &base;
|
|
memory.view.format = "i";
|
|
memory.view.ndim = 2;
|
|
memory.view.itemsize = 4;
|
|
memory.view.len = 24;
|
|
memory.flags = 8;
|
|
memcpy(&before, &memory, sizeof(memory));
|
|
self.view = memory.view;
|
|
self.view.obj = scenario == 0 ? NULL : &base;
|
|
self.view.suboffsets = scenario == 1 ? &offset : NULL;
|
|
memcpy(&original, &self.view, sizeof(original));
|
|
events[0] = '\0';
|
|
result = picklebuf_raw(&self, NULL);
|
|
assert(strcmp(events, expected[scenario]) == 0);
|
|
assert(memcmp(&original, &self.view, sizeof(original)) == 0);
|
|
if (scenario < 4) {
|
|
assert(result == NULL);
|
|
assert(memcmp(&before, &memory, sizeof(memory)) == 0);
|
|
} else {
|
|
assert(result == (PyObject *)&memory);
|
|
assert(memory.view.obj == &base && memory.view.len == 24);
|
|
assert(memory.view.suboffsets == NULL);
|
|
assert(strcmp(memory.view.format, "B") == 0);
|
|
assert(memory.view.ndim == 1 && memory.view.itemsize == 1);
|
|
assert(memory.view.shape == &memory.view.len);
|
|
assert(memory.view.strides == &memory.view.itemsize);
|
|
assert(memory.flags == (_Py_MEMORYVIEW_C | _Py_MEMORYVIEW_FORTRAN));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory(prefix="vc6-picklebuf-raw-") as directory:
|
|
path = Path(directory)
|
|
(path / "test.c").write_text(harness)
|
|
result = subprocess.run([
|
|
"cc", "-std=c89", "-pedantic-errors", "-Wall", "-Wextra", "-Werror",
|
|
"-Wno-unused-parameter", str(path / "test.c"), "-o", str(path / "test"),
|
|
])
|
|
if result.returncode:
|
|
sys.exit(result.returncode)
|
|
subprocess.run([str(path / "test")], check=True)
|
|
print("picklebuf_raw C89 compile and validation/allocation order: PASS (5 cases)")
|