@@ -2883,6 +2883,9 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) {
2883
2883
Py_ssize_t len ;
2884
2884
2885
2885
const char * dt_ptr = PyUnicode_AsUTF8AndSize (dtstr , & len );
2886
+ if (dt_ptr == NULL ) {
2887
+ goto invalid_string_error ;
2888
+ }
2886
2889
2887
2890
int year = 0 , month = 0 , day = 0 ;
2888
2891
@@ -2894,12 +2897,15 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) {
2894
2897
}
2895
2898
2896
2899
if (rv < 0 ) {
2897
- PyErr_Format (PyExc_ValueError , "Invalid isoformat string: %s" ,
2898
- dt_ptr );
2899
- return NULL ;
2900
+ goto invalid_string_error ;
2900
2901
}
2901
2902
2902
2903
return new_date_subclass_ex (year , month , day , cls );
2904
+
2905
+ invalid_string_error :
2906
+ PyErr_Format (PyExc_ValueError , "Invalid isoformat string: %R" ,
2907
+ dtstr );
2908
+ return NULL ;
2903
2909
}
2904
2910
2905
2911
@@ -4258,15 +4264,18 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) {
4258
4264
Py_ssize_t len ;
4259
4265
const char * p = PyUnicode_AsUTF8AndSize (tstr , & len );
4260
4266
4267
+ if (p == NULL ) {
4268
+ goto invalid_string_error ;
4269
+ }
4270
+
4261
4271
int hour = 0 , minute = 0 , second = 0 , microsecond = 0 ;
4262
4272
int tzoffset , tzimicrosecond = 0 ;
4263
4273
int rv = parse_isoformat_time (p , len ,
4264
4274
& hour , & minute , & second , & microsecond ,
4265
4275
& tzoffset , & tzimicrosecond );
4266
4276
4267
4277
if (rv < 0 ) {
4268
- PyErr_Format (PyExc_ValueError , "Invalid isoformat string: %s" , p );
4269
- return NULL ;
4278
+ goto invalid_string_error ;
4270
4279
}
4271
4280
4272
4281
PyObject * tzinfo = tzinfo_from_isoformat_results (rv , tzoffset ,
@@ -4286,6 +4295,10 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) {
4286
4295
4287
4296
Py_DECREF (tzinfo );
4288
4297
return t ;
4298
+
4299
+ invalid_string_error :
4300
+ PyErr_Format (PyExc_ValueError , "Invalid isoformat string: %R" , tstr );
4301
+ return NULL ;
4289
4302
}
4290
4303
4291
4304
@@ -4839,6 +4852,33 @@ datetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
4839
4852
return result ;
4840
4853
}
4841
4854
4855
+ static PyObject *
4856
+ _sanitize_isoformat_str (PyObject * dtstr , int * needs_decref ) {
4857
+ // `fromisoformat` allows surrogate characters in exactly one position,
4858
+ // the separator; to allow datetime_fromisoformat to make the simplifying
4859
+ // assumption that all valid strings can be encoded in UTF-8, this function
4860
+ // replaces any surrogate character separators with `T`.
4861
+ Py_ssize_t len = PyUnicode_GetLength (dtstr );
4862
+ * needs_decref = 0 ;
4863
+ if (len <= 10 || !Py_UNICODE_IS_SURROGATE (PyUnicode_READ_CHAR (dtstr , 10 ))) {
4864
+ return dtstr ;
4865
+ }
4866
+
4867
+ PyObject * str_out = PyUnicode_New (len , PyUnicode_MAX_CHAR_VALUE (dtstr ));
4868
+ if (str_out == NULL ) {
4869
+ return NULL ;
4870
+ }
4871
+
4872
+ if (PyUnicode_CopyCharacters (str_out , 0 , dtstr , 0 , len ) == -1 ||
4873
+ PyUnicode_WriteChar (str_out , 10 , (Py_UCS4 )'T' )) {
4874
+ Py_DECREF (str_out );
4875
+ return NULL ;
4876
+ }
4877
+
4878
+ * needs_decref = 1 ;
4879
+ return str_out ;
4880
+ }
4881
+
4842
4882
static PyObject *
4843
4883
datetime_fromisoformat (PyObject * cls , PyObject * dtstr ) {
4844
4884
assert (dtstr != NULL );
@@ -4848,9 +4888,20 @@ datetime_fromisoformat(PyObject* cls, PyObject *dtstr) {
4848
4888
return NULL ;
4849
4889
}
4850
4890
4891
+ int needs_decref = 0 ;
4892
+ dtstr = _sanitize_isoformat_str (dtstr , & needs_decref );
4893
+ if (dtstr == NULL ) {
4894
+ goto error ;
4895
+ }
4896
+
4851
4897
Py_ssize_t len ;
4852
4898
const char * dt_ptr = PyUnicode_AsUTF8AndSize (dtstr , & len );
4853
- const char * p = dt_ptr ;
4899
+
4900
+ if (dt_ptr == NULL ) {
4901
+ goto invalid_string_error ;
4902
+ }
4903
+
4904
+ const char * p = dt_ptr ;
4854
4905
4855
4906
int year = 0 , month = 0 , day = 0 ;
4856
4907
int hour = 0 , minute = 0 , second = 0 , microsecond = 0 ;
@@ -4883,20 +4934,32 @@ datetime_fromisoformat(PyObject* cls, PyObject *dtstr) {
4883
4934
& tzoffset , & tzusec );
4884
4935
}
4885
4936
if (rv < 0 ) {
4886
- PyErr_Format (PyExc_ValueError , "Invalid isoformat string: %s" , dt_ptr );
4887
- return NULL ;
4937
+ goto invalid_string_error ;
4888
4938
}
4889
4939
4890
4940
PyObject * tzinfo = tzinfo_from_isoformat_results (rv , tzoffset , tzusec );
4891
4941
if (tzinfo == NULL ) {
4892
- return NULL ;
4942
+ goto error ;
4893
4943
}
4894
4944
4895
4945
PyObject * dt = new_datetime_subclass_ex (year , month , day , hour , minute ,
4896
4946
second , microsecond , tzinfo , cls );
4897
4947
4898
4948
Py_DECREF (tzinfo );
4949
+ if (needs_decref ) {
4950
+ Py_DECREF (dtstr );
4951
+ }
4899
4952
return dt ;
4953
+
4954
+ invalid_string_error :
4955
+ PyErr_Format (PyExc_ValueError , "Invalid isoformat string: %R" , dtstr );
4956
+
4957
+ error :
4958
+ if (needs_decref ) {
4959
+ Py_DECREF (dtstr );
4960
+ }
4961
+
4962
+ return NULL ;
4900
4963
}
4901
4964
4902
4965
0 commit comments