Issue #18216: gettext now raises an error when a .mo file has an unsupported major version number. Patch by Aaron Hill.

This commit is contained in:
Antoine Pitrou 2014-10-28 20:17:51 +01:00
parent b7374d0271
commit be8d06f523
5 changed files with 90 additions and 3 deletions

View File

@ -344,9 +344,9 @@ will assume message ids as Unicode strings, not byte strings.
The entire set of key/value pairs are placed into a dictionary and set as the The entire set of key/value pairs are placed into a dictionary and set as the
"protected" :attr:`_info` instance variable. "protected" :attr:`_info` instance variable.
If the :file:`.mo` file's magic number is invalid, or if other problems occur If the :file:`.mo` file's magic number is invalid, the major version number is
while reading the file, instantiating a :class:`GNUTranslations` class can raise unexpected, or if other problems occur while reading the file, instantiating a
:exc:`OSError`. :class:`GNUTranslations` class can raise :exc:`OSError`.
The following methods are overridden from the base class implementation: The following methods are overridden from the base class implementation:

View File

@ -225,6 +225,13 @@ class GNUTranslations(NullTranslations):
LE_MAGIC = 0x950412de LE_MAGIC = 0x950412de
BE_MAGIC = 0xde120495 BE_MAGIC = 0xde120495
# Acceptable .mo versions
VERSIONS = (0, 1)
def _get_versions(self, version):
"""Returns a tuple of major version, minor version"""
return (version >> 16, version & 0xffff)
def _parse(self, fp): def _parse(self, fp):
"""Override this method to support alternative .mo formats.""" """Override this method to support alternative .mo formats."""
unpack = struct.unpack unpack = struct.unpack
@ -245,6 +252,12 @@ class GNUTranslations(NullTranslations):
ii = '>II' ii = '>II'
else: else:
raise OSError(0, 'Bad magic number', filename) raise OSError(0, 'Bad magic number', filename)
major_version, minor_version = self._get_versions(version)
if major_version not in self.VERSIONS:
raise OSError(0, 'Bad version number ' + str(major_version), filename)
# Now put all messages from the .mo file buffer into the catalog # Now put all messages from the .mo file buffer into the catalog
# dictionary. # dictionary.
for i in range(0, msgcount): for i in range(0, msgcount):

View File

@ -33,6 +33,55 @@ IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1
ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA== ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA==
''' '''
# This data contains an invalid major version number (5)
# An unexpected major version number should be treated as an error when
# parsing a .mo file
GNU_MO_DATA_BAD_MAJOR_VERSION = b'''\
3hIElQAABQAGAAAAHAAAAEwAAAALAAAAfAAAAAAAAACoAAAAFQAAAKkAAAAjAAAAvwAAAKEAAADj
AAAABwAAAIUBAAALAAAAjQEAAEUBAACZAQAAFgAAAN8CAAAeAAAA9gIAAKEAAAAVAwAABQAAALcD
AAAJAAAAvQMAAAEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABQAAAAYAAAACAAAAAFJh
eW1vbmQgTHV4dXJ5IFlhY2gtdABUaGVyZSBpcyAlcyBmaWxlAFRoZXJlIGFyZSAlcyBmaWxlcwBU
aGlzIG1vZHVsZSBwcm92aWRlcyBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgbG9jYWxpemF0aW9u
CnN1cHBvcnQgZm9yIHlvdXIgUHl0aG9uIHByb2dyYW1zIGJ5IHByb3ZpZGluZyBhbiBpbnRlcmZh
Y2UgdG8gdGhlIEdOVQpnZXR0ZXh0IG1lc3NhZ2UgY2F0YWxvZyBsaWJyYXJ5LgBtdWxsdXNrAG51
ZGdlIG51ZGdlAFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDAt
MDgtMjkgMTI6MTktMDQ6MDAKTGFzdC1UcmFuc2xhdG9yOiBKLiBEYXZpZCBJYsOhw7FleiA8ai1k
YXZpZEBub29zLmZyPgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpN
SU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4
NTktMQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBub25lCkdlbmVyYXRlZC1CeTogcHlnZXR0
ZXh0LnB5IDEuMQpQbHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0
d29iYmxlciBNYW5ncm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFo
eXIgY2ViaXZxcmYgdmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVn
IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1
ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA==
'''
# This data contains an invalid minor version number (7)
# An unexpected minor version number only indicates that some of the file's
# contents may not be able to be read. It does not indicate an error.
GNU_MO_DATA_BAD_MINOR_VERSION = b'''\
3hIElQcAAAAGAAAAHAAAAEwAAAALAAAAfAAAAAAAAACoAAAAFQAAAKkAAAAjAAAAvwAAAKEAAADj
AAAABwAAAIUBAAALAAAAjQEAAEUBAACZAQAAFgAAAN8CAAAeAAAA9gIAAKEAAAAVAwAABQAAALcD
AAAJAAAAvQMAAAEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABQAAAAYAAAACAAAAAFJh
eW1vbmQgTHV4dXJ5IFlhY2gtdABUaGVyZSBpcyAlcyBmaWxlAFRoZXJlIGFyZSAlcyBmaWxlcwBU
aGlzIG1vZHVsZSBwcm92aWRlcyBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgbG9jYWxpemF0aW9u
CnN1cHBvcnQgZm9yIHlvdXIgUHl0aG9uIHByb2dyYW1zIGJ5IHByb3ZpZGluZyBhbiBpbnRlcmZh
Y2UgdG8gdGhlIEdOVQpnZXR0ZXh0IG1lc3NhZ2UgY2F0YWxvZyBsaWJyYXJ5LgBtdWxsdXNrAG51
ZGdlIG51ZGdlAFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDAt
MDgtMjkgMTI6MTktMDQ6MDAKTGFzdC1UcmFuc2xhdG9yOiBKLiBEYXZpZCBJYsOhw7FleiA8ai1k
YXZpZEBub29zLmZyPgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpN
SU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4
NTktMQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBub25lCkdlbmVyYXRlZC1CeTogcHlnZXR0
ZXh0LnB5IDEuMQpQbHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0
d29iYmxlciBNYW5ncm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFo
eXIgY2ViaXZxcmYgdmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVn
IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1
ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA==
'''
UMO_DATA = b'''\ UMO_DATA = b'''\
3hIElQAAAAACAAAAHAAAACwAAAAFAAAAPAAAAAAAAABQAAAABAAAAFEAAAAPAQAAVgAAAAQAAABm 3hIElQAAAAACAAAAHAAAACwAAAAFAAAAPAAAAAAAAABQAAAABAAAAFEAAAAPAQAAVgAAAAQAAABm
AQAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAYWLDngBQcm9qZWN0LUlkLVZlcnNpb246IDIuMApQTy1S AQAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAYWLDngBQcm9qZWN0LUlkLVZlcnNpb246IDIuMApQTy1S
@ -56,6 +105,8 @@ bGUKR2VuZXJhdGVkLUJ5OiBweWdldHRleHQucHkgMS4zCgA=
LOCALEDIR = os.path.join('xx', 'LC_MESSAGES') LOCALEDIR = os.path.join('xx', 'LC_MESSAGES')
MOFILE = os.path.join(LOCALEDIR, 'gettext.mo') MOFILE = os.path.join(LOCALEDIR, 'gettext.mo')
MOFILE_BAD_MAJOR_VERSION = os.path.join(LOCALEDIR, 'gettext_bad_major_version.mo')
MOFILE_BAD_MINOR_VERSION = os.path.join(LOCALEDIR, 'gettext_bad_minor_version.mo')
UMOFILE = os.path.join(LOCALEDIR, 'ugettext.mo') UMOFILE = os.path.join(LOCALEDIR, 'ugettext.mo')
MMOFILE = os.path.join(LOCALEDIR, 'metadata.mo') MMOFILE = os.path.join(LOCALEDIR, 'metadata.mo')
@ -66,6 +117,10 @@ class GettextBaseTest(unittest.TestCase):
os.makedirs(LOCALEDIR) os.makedirs(LOCALEDIR)
with open(MOFILE, 'wb') as fp: with open(MOFILE, 'wb') as fp:
fp.write(base64.decodebytes(GNU_MO_DATA)) fp.write(base64.decodebytes(GNU_MO_DATA))
with open(MOFILE_BAD_MAJOR_VERSION, 'wb') as fp:
fp.write(base64.decodebytes(GNU_MO_DATA_BAD_MAJOR_VERSION))
with open(MOFILE_BAD_MINOR_VERSION, 'wb') as fp:
fp.write(base64.decodebytes(GNU_MO_DATA_BAD_MINOR_VERSION))
with open(UMOFILE, 'wb') as fp: with open(UMOFILE, 'wb') as fp:
fp.write(base64.decodebytes(UMO_DATA)) fp.write(base64.decodebytes(UMO_DATA))
with open(MMOFILE, 'wb') as fp: with open(MMOFILE, 'wb') as fp:
@ -166,6 +221,21 @@ class GettextTestCase2(GettextBaseTest):
def test_textdomain(self): def test_textdomain(self):
self.assertEqual(gettext.textdomain(), 'gettext') self.assertEqual(gettext.textdomain(), 'gettext')
def test_bad_major_version(self):
with open(MOFILE_BAD_MAJOR_VERSION, 'rb') as fp:
with self.assertRaises(OSError) as cm:
gettext.GNUTranslations(fp)
exception = cm.exception
self.assertEqual(exception.errno, 0)
self.assertEqual(exception.strerror, "Bad version number 5")
self.assertEqual(exception.filename, MOFILE_BAD_MAJOR_VERSION)
def test_bad_minor_version(self):
with open(MOFILE_BAD_MINOR_VERSION, 'rb') as fp:
# Check that no error is thrown with a bad minor version number
gettext.GNUTranslations(fp)
def test_some_translations(self): def test_some_translations(self):
eq = self.assertEqual eq = self.assertEqual
# test some translations # test some translations

View File

@ -567,6 +567,7 @@ Kevan Heydon
Wouter van Heyst Wouter van Heyst
Kelsey Hightower Kelsey Hightower
Jason Hildebrand Jason Hildebrand
Aaron Hill
Richie Hindle Richie Hindle
Konrad Hinsen Konrad Hinsen
David Hobley David Hobley

View File

@ -181,6 +181,9 @@ Core and Builtins
Library Library
------- -------
- Issue #18216: gettext now raises an error when a .mo file has an
unsupported major version number. Patch by Aaron Hill.
- Issue #13918: Provide a locale.delocalize() function which can remove - Issue #13918: Provide a locale.delocalize() function which can remove
locale-specific number formatting from a string representing a number, locale-specific number formatting from a string representing a number,
without then converting it to a specific type. Patch by Cédric Krier. without then converting it to a specific type. Patch by Cédric Krier.