1818#include <stdlib.h>
1919#include <inttypes.h>
2020
21+ #if defined(_Py_FUZZ_ONE ) && defined(_Py_FUZZ_fuzz_tokenizer ) && \
22+ defined(HAVE_TMPFILE ) && !defined(Py_ENABLE_SHARED )
23+ # define FUZZ_TOKENIZER_FILE 1
24+ # include "../../Include/internal/pycore_token.h"
25+ # include "../../Parser/tokenizer/tokenizer.h"
26+ #endif
27+
2128/* Fuzz PyFloat_FromString as a proxy for float(str). */
2229static int fuzz_builtin_float (const char * data , size_t size ) {
2330 PyObject * s = PyBytes_FromStringAndSize (data , size );
@@ -623,7 +630,6 @@ clear_expected_tokenizer_error(void)
623630 if (PyErr_ExceptionMatches (PyExc_SyntaxError ) ||
624631 PyErr_ExceptionMatches (PyExc_UnicodeError ) ||
625632 PyErr_ExceptionMatches (PyExc_LookupError ) ||
626- PyErr_ExceptionMatches (PyExc_MemoryError ) ||
627633 PyErr_ExceptionMatches (PyExc_Warning )) {
628634 PyErr_Clear ();
629635 return ;
@@ -632,6 +638,82 @@ clear_expected_tokenizer_error(void)
632638 abort ();
633639}
634640
641+ #ifdef FUZZ_TOKENIZER_FILE
642+ static int
643+ fuzz_tokenizer_file (const char * data , size_t size , unsigned char options )
644+ {
645+ FILE * fp = tmpfile ();
646+ if (fp == NULL ) {
647+ return 0 ;
648+ }
649+ if ((size != 0 && fwrite (data , 1 , size , fp ) != size ) ||
650+ fseek (fp , 0 , SEEK_SET ) != 0 ) {
651+ fclose (fp );
652+ return 0 ;
653+ }
654+
655+ PyObject * filename = PyUnicode_FromString ("<fuzz input>" );
656+ if (filename == NULL ) {
657+ fclose (fp );
658+ clear_expected_tokenizer_error ();
659+ return 1 ;
660+ }
661+ _PyTok_Config config = {
662+ .kind = _PYTOK_SOURCE_FILE ,
663+ .source .file = {fp , NULL , NULL , NULL },
664+ .extra_tokens = options & 0x02 ,
665+ .filename = filename ,
666+ };
667+ PyTokenizer * tok = _PyTok_New (& config );
668+ if (tok == NULL ) {
669+ _PyTok_RaiseInitError (filename );
670+ Py_DECREF (filename );
671+ fclose (fp );
672+ clear_expected_tokenizer_error ();
673+ return 1 ;
674+ }
675+ Py_DECREF (filename );
676+
677+ int terminated = 0 ;
678+ size_t limit = size * 4 + 32 ;
679+ for (size_t i = 0 ; i < limit ; i ++ ) {
680+ _PyTok_Token token ;
681+ _PyTok_TokenInit (& token );
682+ if (_PyTok_Get (tok , & token ) == _PYTOK_ERROR ) {
683+ _PyTok_TokenClear (& token );
684+ _PyTok_RaiseError (tok );
685+ clear_expected_tokenizer_error ();
686+ terminated = 1 ;
687+ break ;
688+ }
689+ int type = token .type ;
690+ Py_ssize_t token_len ;
691+ _PyTok_Loc start ;
692+ _PyTok_Loc end ;
693+ if (_PyTok_TokenView (tok , & token , & token_len ) == NULL ||
694+ token_len < 0 ||
695+ _PyTok_TokenTextLocations (tok , & token , & start , & end ) < 0 ||
696+ start .lineno < 1 || start .byte_col < -1 ||
697+ end .lineno < start .lineno || end .byte_col < -1 ||
698+ (end .lineno == start .lineno &&
699+ end .byte_col < start .byte_col )) {
700+ abort ();
701+ }
702+ _PyTok_TokenClear (& token );
703+ if (type == ENDMARKER ) {
704+ terminated = 1 ;
705+ break ;
706+ }
707+ }
708+ _PyTok_Free (tok );
709+ fclose (fp );
710+ if (!terminated ) {
711+ abort ();
712+ }
713+ return 1 ;
714+ }
715+ #endif
716+
635717static int
636718fuzz_tokenizer (const char * data , size_t size )
637719{
@@ -643,6 +725,12 @@ fuzz_tokenizer(const char *data, size_t size)
643725 data ++ ;
644726 size -- ;
645727
728+ #ifdef FUZZ_TOKENIZER_FILE
729+ if ((options & 0x04 ) && fuzz_tokenizer_file (data , size , options )) {
730+ return 0 ;
731+ }
732+ #endif
733+
646734 int bytes_mode = options & 0x01 ;
647735 PyObject * source ;
648736 if (bytes_mode ) {
0 commit comments