port: advance VC6 typeobject frontier and preserve regression coverage
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compile the exact setiter_reduce as C89 and check ownership and call 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 \*\nsetiter_reduce\([^\n]+\)\n\{.*?\n\}", source, re.S
|
||||
)
|
||||
assert match, "setiter_reduce not found"
|
||||
harness = r'''
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
typedef struct { int refs; } PyObject;
|
||||
typedef struct {
|
||||
PyObject head;
|
||||
PyObject *si_set;
|
||||
long si_used, si_pos, len;
|
||||
} setiterobject;
|
||||
#define Py_UNUSED(name) name
|
||||
#define _Py_ID(name) name
|
||||
static int iter, mode, exhausted;
|
||||
static PyObject backing, list_value, builtin, built;
|
||||
static setiterobject original;
|
||||
static char events[32];
|
||||
static void event(char c) {
|
||||
size_t n = strlen(events);
|
||||
assert(n + 1 < sizeof(events));
|
||||
events[n] = c;
|
||||
events[n + 1] = '\0';
|
||||
}
|
||||
static void Py_XINCREF(PyObject *obj) {
|
||||
assert(obj == original.si_set);
|
||||
assert(strcmp(events, "") == 0);
|
||||
event('I');
|
||||
if (obj != NULL) ++obj->refs;
|
||||
}
|
||||
static void Py_XDECREF(PyObject *obj) {
|
||||
assert(obj == (mode == 1 ? NULL : original.si_set));
|
||||
assert(strcmp(events, "IL") == 0);
|
||||
event('D');
|
||||
if (obj != NULL) --obj->refs;
|
||||
}
|
||||
static PyObject *PySequence_List(PyObject *obj) {
|
||||
setiterobject *tmp = (setiterobject *)obj;
|
||||
assert(tmp != &original);
|
||||
assert(tmp->head.refs == original.head.refs);
|
||||
assert(tmp->si_set == original.si_set);
|
||||
assert(tmp->si_used == original.si_used);
|
||||
assert(tmp->si_pos == original.si_pos && tmp->len == original.len);
|
||||
assert(backing.refs == (exhausted ? 1 : 2));
|
||||
assert(strcmp(events, "I") == 0);
|
||||
event('L');
|
||||
tmp->si_pos = 99;
|
||||
tmp->len = 0;
|
||||
if (mode == 1 && tmp->si_set != NULL) {
|
||||
--tmp->si_set->refs;
|
||||
tmp->si_set = NULL;
|
||||
}
|
||||
return mode == 2 ? NULL : &list_value;
|
||||
}
|
||||
static PyObject *_PyEval_GetBuiltin(int *name) {
|
||||
assert(name == &iter);
|
||||
assert(strcmp(events, "ILD") == 0 && backing.refs == 1);
|
||||
event('G');
|
||||
return &builtin;
|
||||
}
|
||||
static PyObject *Py_BuildValue(const char *format, PyObject *func, PyObject *list) {
|
||||
assert(strcmp(format, "N(N)") == 0);
|
||||
assert(func == &builtin && list == &list_value);
|
||||
assert(strcmp(events, "ILDG") == 0 && backing.refs == 1);
|
||||
event('B');
|
||||
--func->refs;
|
||||
--list->refs;
|
||||
return mode == 3 ? NULL : &built;
|
||||
}
|
||||
'''
|
||||
harness += match.group(0)
|
||||
harness += r'''
|
||||
int main(void) {
|
||||
setiterobject before;
|
||||
PyObject *result;
|
||||
for (exhausted = 0; exhausted < 2; ++exhausted) {
|
||||
for (mode = 0; mode < 4; ++mode) {
|
||||
backing.refs = list_value.refs = builtin.refs = 1;
|
||||
memset(&original, 0, sizeof(original));
|
||||
original.head.refs = 7;
|
||||
original.si_set = exhausted ? NULL : &backing;
|
||||
original.si_used = 5;
|
||||
original.si_pos = 2;
|
||||
original.len = 3;
|
||||
memcpy(&before, &original, sizeof(before));
|
||||
events[0] = '\0';
|
||||
result = setiter_reduce(&original, NULL);
|
||||
assert(memcmp(&before, &original, sizeof(before)) == 0);
|
||||
assert(backing.refs == 1);
|
||||
assert(strcmp(events, mode == 2 ? "ILD" : "ILDGB") == 0);
|
||||
assert(result == (mode >= 2 ? NULL : &built));
|
||||
assert(list_value.refs == (mode == 2 ? 1 : 0));
|
||||
assert(builtin.refs == (mode == 2 ? 1 : 0));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
with tempfile.TemporaryDirectory(prefix="vc6-setiter-reduce-") 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("setiter_reduce C89 declaration/evaluation/cleanup/return: PASS (8 cases)")
|
||||
Reference in New Issue
Block a user