The convention with the Python C API is to return a non-NULL pointer to a python object on success, and return NULL and set the exception global variable on error. Yes, global variables are also alive and well.
PyObject *fout = _PySys_GetObjectId(&PyId_stdout);
stdout_encoding = _PyObject_GetAttrId(fout, &PyId_encoding);
The python equivalent of this is `sys.stdout.encoding`. The StringIO object was constructed without an encoding, so this is None. stdout_encoding_str = PyUnicode_AsUTF8(stdout_encoding);
This tries to convert None to a C string, which fails.