From 5900305addd2cc1c484b0d1e3263191d207f1066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Wed, 28 Mar 2012 15:15:10 +0200 Subject: Pre-validate numerus rules: fail early, fail gracefully Change-Id: Ibb3d27b9ff3d2f356a7c5c98b98686342f001f8f Reviewed-by: Oswald Buddenhagen --- src/corelib/kernel/qtranslator.cpp | 97 +++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 17 deletions(-) (limited to 'src/corelib/kernel/qtranslator.cpp') diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 217f99e270..4af932aac9 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -130,14 +130,82 @@ static uint elfHash(const char *name) return hash; } -static int numerusHelper(int n, const uchar *rules, uint rulesSize) +/* + \internal + + Determines whether \a rules are valid "numerus rules". Test input with this + function before calling numerusHelper, below. + */ +static bool isValidNumerusRules(const uchar *rules, uint rulesSize) { -#define CHECK_RANGE \ - do { \ - if (i >= rulesSize) \ - return -1; \ - } while (0) + // Disabled computation of maximum numerus return value + // quint32 numerus = 0; + + if (rulesSize == 0) + return true; + + quint32 offset = 0; + do { + uchar opcode = rules[offset]; + uchar op = opcode & Q_OP_MASK; + + if (opcode & 0x80) + return false; // Bad op + + if (++offset == rulesSize) + return false; // Missing operand + + // right operand + ++offset; + + switch (op) + { + case Q_EQ: + case Q_LT: + case Q_LEQ: + break; + + case Q_BETWEEN: + if (offset != rulesSize) { + // third operand + ++offset; + break; + } + return false; // Missing operand + + default: + return false; // Bad op (0) + } + // ++numerus; + if (offset == rulesSize) + return true; + + } while (((rules[offset] == Q_AND) + || (rules[offset] == Q_OR) + || (rules[offset] == Q_NEWRULE)) + && ++offset != rulesSize); + + // Bad op + return false; +} + +/* + \internal + + This function does no validation of input and assumes it is well-behaved, + these assumptions can be checked with isValidNumerusRules, above. + + Determines which translation to use based on the value of \a n. The return + value is an index identifying the translation to be used. + + \a rules is a character array of size \a rulesSize containing bytecode that + operates on the value of \a n and ultimately determines the result. + + This function has O(1) space and O(rulesSize) time complexity. + */ +static int numerusHelper(int n, const uchar *rules, uint rulesSize) +{ int result = 0; uint i = 0; @@ -152,8 +220,6 @@ static int numerusHelper(int n, const uchar *rules, uint rulesSize) for (;;) { bool truthValue = true; - - CHECK_RANGE; int opcode = rules[i++]; int leftOperand = n; @@ -167,13 +233,9 @@ static int numerusHelper(int n, const uchar *rules, uint rulesSize) } int op = opcode & Q_OP_MASK; - - CHECK_RANGE; int rightOperand = rules[i++]; switch (op) { - default: - return -1; case Q_EQ: truthValue = (leftOperand == rightOperand); break; @@ -183,9 +245,8 @@ static int numerusHelper(int n, const uchar *rules, uint rulesSize) case Q_LEQ: truthValue = (leftOperand <= rightOperand); break; - case Q_BETWEEN: + case Q_BETWEEN: int bottom = rightOperand; - CHECK_RANGE; int top = rules[i++]; truthValue = (leftOperand >= bottom && leftOperand <= top); } @@ -215,10 +276,10 @@ static int numerusHelper(int n, const uchar *rules, uint rulesSize) if (i == rulesSize) return result; - if (rules[i++] != Q_NEWRULE) - break; + i++; // Q_NEWRULE } - return -1; + + Q_ASSERT(false); } class QTranslatorPrivate : public QObjectPrivate @@ -738,6 +799,8 @@ bool QTranslatorPrivate::do_load(const uchar *data, int len) if (!offsetArray || !messageArray) ok = false; + if (!isValidNumerusRules(numerusRulesArray, numerusRulesLength)) + ok = false; if (!ok) { messageArray = 0; -- cgit v1.2.3