port: advance VC6 typeobject frontier and preserve regression coverage
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compile exact odictiter_reduce as C89 and check timing and ownership."""
|
||||
|
||||
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 \*\nodictiter_reduce\(odictiterobject \*di, PyObject \*Py_UNUSED\(ignored\)\)\n\{.*?\n\}",
|
||||
source, re.S,
|
||||
)
|
||||
assert match, "odictiter_reduce definition not found"
|
||||
harness = r'''
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
typedef struct { int refs; } PyObject;
|
||||
typedef struct { PyObject *di_odict, *di_current; int position; } odictiterobject;
|
||||
static PyObject dict, current, list_obj, builtin, result_obj;
|
||||
static odictiterobject *original;
|
||||
static int stage, failure, consume;
|
||||
static int iter;
|
||||
#define Py_UNUSED(name) unused
|
||||
#define _Py_ID(name) name
|
||||
static void Py_XINCREF(PyObject *obj) {
|
||||
assert(stage < 2);
|
||||
assert(obj == (stage == 0 ? original->di_odict : original->di_current));
|
||||
if (obj != NULL) ++obj->refs;
|
||||
++stage;
|
||||
}
|
||||
static PyObject *PySequence_List(PyObject *obj) {
|
||||
odictiterobject *tmp = (odictiterobject *)obj;
|
||||
assert(stage == 2 && tmp != original);
|
||||
assert(tmp->di_odict == original->di_odict);
|
||||
assert(tmp->di_current == original->di_current);
|
||||
assert(tmp->position == 17);
|
||||
assert(dict.refs == (original->di_odict ? 2 : 1));
|
||||
assert(current.refs == (original->di_current ? 2 : 1));
|
||||
tmp->position = 99;
|
||||
if (consume) {
|
||||
if (tmp->di_odict) --tmp->di_odict->refs;
|
||||
if (tmp->di_current) --tmp->di_current->refs;
|
||||
tmp->di_odict = tmp->di_current = NULL;
|
||||
}
|
||||
stage = 3;
|
||||
list_obj.refs = failure == 1 ? 0 : 1;
|
||||
return failure == 1 ? NULL : &list_obj;
|
||||
}
|
||||
static void Py_XDECREF(PyObject *obj) {
|
||||
assert(stage == 3 || stage == 4);
|
||||
assert(obj == (consume ? NULL : (stage == 3 ? original->di_odict : original->di_current)));
|
||||
if (obj != NULL) --obj->refs;
|
||||
++stage;
|
||||
}
|
||||
static PyObject *_PyEval_GetBuiltin(int *id) {
|
||||
assert(stage == 5 && id == &iter && failure != 1);
|
||||
assert(dict.refs == 1 && current.refs == 1);
|
||||
stage = 6;
|
||||
builtin.refs = 1;
|
||||
return &builtin;
|
||||
}
|
||||
static PyObject *Py_BuildValue(const char *format, PyObject *func, PyObject *list) {
|
||||
assert(stage == 6 && strcmp(format, "N(N)") == 0);
|
||||
assert(func == &builtin && list == &list_obj);
|
||||
assert(func->refs == 1 && list->refs == 1);
|
||||
--func->refs;
|
||||
--list->refs;
|
||||
stage = 7;
|
||||
return failure == 2 ? NULL : &result_obj;
|
||||
}
|
||||
'''
|
||||
harness += match.group(0)
|
||||
harness += r'''
|
||||
int main(void) {
|
||||
int mask;
|
||||
odictiterobject di;
|
||||
PyObject *result;
|
||||
for (mask = 0; mask < 4; ++mask) {
|
||||
for (consume = 0; consume < 2; ++consume) {
|
||||
for (failure = 0; failure < 3; ++failure) {
|
||||
dict.refs = current.refs = 1;
|
||||
di.di_odict = mask & 1 ? &dict : NULL;
|
||||
di.di_current = mask & 2 ? ¤t : NULL;
|
||||
di.position = 17;
|
||||
original = &di;
|
||||
stage = 0;
|
||||
result = odictiter_reduce(&di, NULL);
|
||||
assert(result == (failure ? NULL : &result_obj));
|
||||
assert(stage == (failure == 1 ? 5 : 7));
|
||||
assert(dict.refs == 1 && current.refs == 1);
|
||||
assert(list_obj.refs == 0);
|
||||
assert(di.di_odict == (mask & 1 ? &dict : NULL));
|
||||
assert(di.di_current == (mask & 2 ? ¤t : NULL));
|
||||
assert(di.position == 17);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
with tempfile.TemporaryDirectory(prefix="vc6-odict-list-") as directory:
|
||||
path = Path(directory)
|
||||
(path / "test.c").write_text(harness)
|
||||
compiled = subprocess.run([
|
||||
"cc", "-std=c89", "-pedantic-errors", "-Wall", "-Wextra", "-Werror",
|
||||
"-Wno-unused-parameter", str(path / "test.c"), "-o", str(path / "test"),
|
||||
])
|
||||
if compiled.returncode:
|
||||
sys.exit(compiled.returncode)
|
||||
subprocess.run([str(path / "test")], check=True)
|
||||
print("odictiter_reduce C89 compile and copy/incref/list/cleanup/ownership/failure order: PASS (24 cases)")
|
||||
Reference in New Issue
Block a user