Skip to content

Commit 90897ef

Browse files
Exclude print_state on Windows to fix access violation
On Windows, _dup() shares the underlying OS handle rather than creating an independent copy. When fclose() closes the dup'd FILE*, it invalidates the original handle, causing an access violation when Python later closes its file object. Since print_state is only a debugging tool, exclude it on Windows via #ifndef _WIN32.
1 parent 822ff4c commit 90897ef

2 files changed

Lines changed: 15 additions & 1 deletion

File tree

tests/test_cpython_interface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def example_encoder(num_variants=1, num_samples=0, add_info=True):
8080
return encoder
8181

8282

83-
@pytest.mark.skipif(sys.platform == "win32", reason="Broken on Windows")
83+
@pytest.mark.skipif(sys.platform == "win32", reason="Not implemented on Windows")
8484
class TestPrintState:
8585
def test_nomimal_case(self, tmp_path):
8686
encoder = example_encoder()

vcztools/_vcztoolsmodule.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ handle_library_error(int err)
3333
}
3434
}
3535

36+
/* The dup/fdopen/fclose pattern used by make_file does not work on Windows
37+
* because _dup shares the underlying OS handle rather than duplicating it.
38+
* When fclose closes the duped FILE*, it invalidates the original handle,
39+
* causing an access violation when Python later closes its file object.
40+
* Since print_state is only a debugging tool, we simply exclude it on Windows. */
41+
#ifndef _WIN32
42+
3643
static FILE *
3744
make_file(PyObject *fileobj, const char *mode)
3845
{
@@ -60,6 +67,8 @@ make_file(PyObject *fileobj, const char *mode)
6067
return ret;
6168
}
6269

70+
#endif /* !_WIN32 */
71+
6372
/*===================================================================
6473
* VcfEncoder
6574
*===================================================================
@@ -474,6 +483,7 @@ VcfEncoder_encode(VcfEncoder *self, PyObject *args)
474483
return ret;
475484
}
476485

486+
#ifndef _WIN32
477487
static PyObject *
478488
VcfEncoder_print_state(VcfEncoder *self, PyObject *args)
479489
{
@@ -500,6 +510,8 @@ VcfEncoder_print_state(VcfEncoder *self, PyObject *args)
500510
return ret;
501511
}
502512

513+
#endif /* !_WIN32 */
514+
503515
/* Return a copy of the dictionary of arrays providing the memory backing.
504516
* Note that we return copy of the Dictionary here so that the arrays themselves
505517
* can't be removed from it.
@@ -524,10 +536,12 @@ static PyGetSetDef VcfEncoder_getsetters[] = {
524536
};
525537

526538
static PyMethodDef VcfEncoder_methods[] = {
539+
#ifndef _WIN32
527540
{ .ml_name = "print_state",
528541
.ml_meth = (PyCFunction) VcfEncoder_print_state,
529542
.ml_flags = METH_VARARGS,
530543
.ml_doc = "Debug method to print out the low-level state" },
544+
#endif
531545
{ .ml_name = "add_info_field",
532546
.ml_meth = (PyCFunction) VcfEncoder_add_info_field,
533547
.ml_flags = METH_VARARGS,

0 commit comments

Comments
 (0)