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