xmlParseReference in parser.c passes ctxt instead of ctxt->userData to the SAX characters / cdataBlock callbacks when emitting the first or last text child of a cached entity tree (parser.c). Every other SAX callsite in the same file correctly passes ctxt->userData. When xmlSchemaSAXPlug is active, which is the case for every user of xmlTextReaderSetSchema / xmlTextReaderSchemaValidate and for lxml's XMLParser(schema=...), ctxt->userData has been swapped to a _xmlSchemaSAXPlug *. Handing the confused charactersSplit handler a raw xmlParserCtxt * causes it to dereference ctxt->myDoc as the forwarded SAX handler and call myDoc->URL as a function pointer, producing a reliable SIGSEGV on the first internal-entity reference in any XSD-validated document. If myDoc->URL is NULL, the secondary path (xmlSchemaSAXHandleText with a garbage plug pointer) crashes instead.