Mercurial > cpython-lru_cache-weakref
comparison Python/codecs.c @ 87338:d68df99d7a57
Issue #19619: Blacklist non-text codecs in method API
str.encode, bytes.decode and bytearray.decode now use an
internal API to throw LookupError for known non-text encodings,
rather than attempting the encoding or decoding operation and
then throwing a TypeError for an unexpected output type.
The latter mechanism remains in place for third party non-text
encodings.
| author | Nick Coghlan <ncoghlan@gmail.com> |
|---|---|
| date | Fri, 22 Nov 2013 22:39:36 +1000 |
| parents | 0d9624f2ff43 |
| children |
comparison
equal
deleted
inserted
replaced
| 87337:90d4153728f6 | 87338:d68df99d7a57 |
|---|---|
| 351 /* Encode an object (e.g. an Unicode object) using the given encoding | 351 /* Encode an object (e.g. an Unicode object) using the given encoding |
| 352 and return the resulting encoded object (usually a Python string). | 352 and return the resulting encoded object (usually a Python string). |
| 353 | 353 |
| 354 errors is passed to the encoder factory as argument if non-NULL. */ | 354 errors is passed to the encoder factory as argument if non-NULL. */ |
| 355 | 355 |
| 356 PyObject *PyCodec_Encode(PyObject *object, | 356 static PyObject * |
| 357 const char *encoding, | 357 _PyCodec_EncodeInternal(PyObject *object, |
| 358 const char *errors) | 358 PyObject *encoder, |
| 359 { | 359 const char *encoding, |
| 360 PyObject *encoder = NULL; | 360 const char *errors) |
| 361 { | |
| 361 PyObject *args = NULL, *result = NULL; | 362 PyObject *args = NULL, *result = NULL; |
| 362 PyObject *v = NULL; | 363 PyObject *v = NULL; |
| 363 | |
| 364 encoder = PyCodec_Encoder(encoding); | |
| 365 if (encoder == NULL) | |
| 366 goto onError; | |
| 367 | 364 |
| 368 args = args_tuple(object, errors); | 365 args = args_tuple(object, errors); |
| 369 if (args == NULL) | 366 if (args == NULL) |
| 370 goto onError; | 367 goto onError; |
| 371 | 368 |
| 400 /* Decode an object (usually a Python string) using the given encoding | 397 /* Decode an object (usually a Python string) using the given encoding |
| 401 and return an equivalent object (e.g. an Unicode object). | 398 and return an equivalent object (e.g. an Unicode object). |
| 402 | 399 |
| 403 errors is passed to the decoder factory as argument if non-NULL. */ | 400 errors is passed to the decoder factory as argument if non-NULL. */ |
| 404 | 401 |
| 405 PyObject *PyCodec_Decode(PyObject *object, | 402 static PyObject * |
| 406 const char *encoding, | 403 _PyCodec_DecodeInternal(PyObject *object, |
| 407 const char *errors) | 404 PyObject *decoder, |
| 408 { | 405 const char *encoding, |
| 409 PyObject *decoder = NULL; | 406 const char *errors) |
| 407 { | |
| 410 PyObject *args = NULL, *result = NULL; | 408 PyObject *args = NULL, *result = NULL; |
| 411 PyObject *v; | 409 PyObject *v; |
| 412 | |
| 413 decoder = PyCodec_Decoder(encoding); | |
| 414 if (decoder == NULL) | |
| 415 goto onError; | |
| 416 | 410 |
| 417 args = args_tuple(object, errors); | 411 args = args_tuple(object, errors); |
| 418 if (args == NULL) | 412 if (args == NULL) |
| 419 goto onError; | 413 goto onError; |
| 420 | 414 |
| 441 onError: | 435 onError: |
| 442 Py_XDECREF(args); | 436 Py_XDECREF(args); |
| 443 Py_XDECREF(decoder); | 437 Py_XDECREF(decoder); |
| 444 Py_XDECREF(result); | 438 Py_XDECREF(result); |
| 445 return NULL; | 439 return NULL; |
| 440 } | |
| 441 | |
| 442 /* Generic encoding/decoding API */ | |
| 443 PyObject *PyCodec_Encode(PyObject *object, | |
| 444 const char *encoding, | |
| 445 const char *errors) | |
| 446 { | |
| 447 PyObject *encoder; | |
| 448 | |
| 449 encoder = PyCodec_Encoder(encoding); | |
| 450 if (encoder == NULL) | |
| 451 return NULL; | |
| 452 | |
| 453 return _PyCodec_EncodeInternal(object, encoder, encoding, errors); | |
| 454 } | |
| 455 | |
| 456 PyObject *PyCodec_Decode(PyObject *object, | |
| 457 const char *encoding, | |
| 458 const char *errors) | |
| 459 { | |
| 460 PyObject *decoder; | |
| 461 | |
| 462 decoder = PyCodec_Decoder(encoding); | |
| 463 if (decoder == NULL) | |
| 464 return NULL; | |
| 465 | |
| 466 return _PyCodec_DecodeInternal(object, decoder, encoding, errors); | |
| 467 } | |
| 468 | |
| 469 /* Text encoding/decoding API */ | |
| 470 static | |
| 471 PyObject *codec_getitem_checked(const char *encoding, | |
| 472 const char *operation_name, | |
| 473 int index) | |
| 474 { | |
| 475 _Py_IDENTIFIER(_is_text_encoding); | |
| 476 PyObject *codec; | |
| 477 PyObject *attr; | |
| 478 PyObject *v; | |
| 479 int is_text_codec; | |
| 480 | |
| 481 codec = _PyCodec_Lookup(encoding); | |
| 482 if (codec == NULL) | |
| 483 return NULL; | |
| 484 | |
| 485 /* Backwards compatibility: assume any raw tuple describes a text | |
| 486 * encoding, and the same for anything lacking the private | |
| 487 * attribute. | |
| 488 */ | |
| 489 if (!PyTuple_CheckExact(codec)) { | |
| 490 attr = _PyObject_GetAttrId(codec, &PyId__is_text_encoding); | |
| 491 if (attr == NULL) { | |
| 492 if (PyErr_ExceptionMatches(PyExc_AttributeError)) { | |
| 493 PyErr_Clear(); | |
| 494 } else { | |
| 495 Py_DECREF(codec); | |
| 496 return NULL; | |
| 497 } | |
| 498 } else { | |
| 499 is_text_codec = PyObject_IsTrue(attr); | |
| 500 Py_DECREF(attr); | |
| 501 if (!is_text_codec) { | |
| 502 Py_DECREF(codec); | |
| 503 PyErr_Format(PyExc_LookupError, | |
| 504 "'%.400s' is not a text encoding; " | |
| 505 "use codecs.%s() to handle arbitrary codecs", | |
| 506 encoding, operation_name); | |
| 507 return NULL; | |
| 508 } | |
| 509 } | |
| 510 } | |
| 511 | |
| 512 v = PyTuple_GET_ITEM(codec, index); | |
| 513 Py_DECREF(codec); | |
| 514 Py_INCREF(v); | |
| 515 return v; | |
| 516 } | |
| 517 | |
| 518 static PyObject * _PyCodec_TextEncoder(const char *encoding) | |
| 519 { | |
| 520 return codec_getitem_checked(encoding, "encode", 0); | |
| 521 } | |
| 522 | |
| 523 static PyObject * _PyCodec_TextDecoder(const char *encoding) | |
| 524 { | |
| 525 return codec_getitem_checked(encoding, "decode", 1); | |
| 526 } | |
| 527 | |
| 528 PyObject *_PyCodec_EncodeText(PyObject *object, | |
| 529 const char *encoding, | |
| 530 const char *errors) | |
| 531 { | |
| 532 PyObject *encoder; | |
| 533 | |
| 534 encoder = _PyCodec_TextEncoder(encoding); | |
| 535 if (encoder == NULL) | |
| 536 return NULL; | |
| 537 | |
| 538 return _PyCodec_EncodeInternal(object, encoder, encoding, errors); | |
| 539 } | |
| 540 | |
| 541 PyObject *_PyCodec_DecodeText(PyObject *object, | |
| 542 const char *encoding, | |
| 543 const char *errors) | |
| 544 { | |
| 545 PyObject *decoder; | |
| 546 | |
| 547 decoder = _PyCodec_TextDecoder(encoding); | |
| 548 if (decoder == NULL) | |
| 549 return NULL; | |
| 550 | |
| 551 return _PyCodec_DecodeInternal(object, decoder, encoding, errors); | |
| 446 } | 552 } |
| 447 | 553 |
| 448 /* Register the error handling callback function error under the name | 554 /* Register the error handling callback function error under the name |
| 449 name. This function will be called by the codec when it encounters | 555 name. This function will be called by the codec when it encounters |
| 450 an unencodable characters/undecodable bytes and doesn't know the | 556 an unencodable characters/undecodable bytes and doesn't know the |
