Skip to content
Snippets Groups Projects
Commit fb3a2dfa authored by Serge Petrenko's avatar Serge Petrenko Committed by Vladimir Davydov
Browse files

decimal: fix encoding numbers with positive exponent.

When a number having a positive exponent is encoded, the internal
decPackedFromNumber function returns a negative scale, which differs
from the scale, returned by decimal_scale(). This leads to errors in
decoding. Account for negative scale in decimal_pack() and
decimal_unpack().

Follow-up #692
parent 3c6c1cc9
No related branches found
No related tags found
No related merge requests found
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "third_party/decNumber/decContext.h" #include "third_party/decNumber/decContext.h"
#include "third_party/decNumber/decPacked.h" #include "third_party/decNumber/decPacked.h"
#include "lib/core/tt_static.h" #include "lib/core/tt_static.h"
#include "lib/msgpuck/msgpuck.h"
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <float.h> /* DBL_DIG */ #include <float.h> /* DBL_DIG */
...@@ -339,20 +340,27 @@ decimal_sqrt(decimal_t *res, const decimal_t *lhs) ...@@ -339,20 +340,27 @@ decimal_sqrt(decimal_t *res, const decimal_t *lhs)
uint32_t uint32_t
decimal_len(const decimal_t *dec) decimal_len(const decimal_t *dec)
{ {
/* 1 + ceil((digits + 1) / 2) */ uint32_t sizeof_scale = dec->exponent > 0 ? mp_sizeof_int(-dec->exponent) :
return 2 + dec->digits / 2; mp_sizeof_uint(-dec->exponent);
/* sizeof_scale + ceil((digits + 1) / 2) */
return sizeof_scale + 1 + dec->digits / 2;
} }
char * char *
decimal_pack(char *data, const decimal_t *dec) decimal_pack(char *data, const decimal_t *dec)
{ {
uint32_t len = decimal_len(dec); uint32_t len = decimal_len(dec);
*data++ = decimal_scale(dec); char *svp = data;
len--; /* encode scale */
if (dec->exponent > 0) {
data = mp_encode_int(data, -dec->exponent);
} else {
data = mp_encode_uint(data, -dec->exponent);
}
len -= data - svp;
int32_t scale; int32_t scale;
char *tmp = (char *)decPackedFromNumber((uint8_t *)data, len, &scale, dec); char *tmp = (char *)decPackedFromNumber((uint8_t *)data, len, &scale, dec);
assert(tmp == data); assert(tmp == data);
assert(scale == (int32_t)decimal_scale(dec));
(void)tmp; (void)tmp;
data += len; data += len;
return data; return data;
...@@ -361,12 +369,30 @@ decimal_pack(char *data, const decimal_t *dec) ...@@ -361,12 +369,30 @@ decimal_pack(char *data, const decimal_t *dec)
decimal_t * decimal_t *
decimal_unpack(const char **data, uint32_t len, decimal_t *dec) decimal_unpack(const char **data, uint32_t len, decimal_t *dec)
{ {
int32_t scale = *((*data)++); int32_t scale;
len--; const char *svp = *data;
if (mp_typeof(**data) == MP_UINT) {
scale = mp_decode_uint(data);
} else if (mp_typeof(**data) == MP_INT) {
scale = mp_decode_int(data);
} else {
return NULL;
}
/*
* scale = -exponent. The exponent should be in range
* [-DECIMAL_MAX_DIGITS; DECIMAL_MAX_DIGITS)
*/
if (scale > DECIMAL_MAX_DIGITS ||
scale <= -DECIMAL_MAX_DIGITS) {
*data = svp;
return NULL;
}
len -= *data - svp;
decimal_t *res = decPackedToNumber((uint8_t *)*data, len, &scale, dec); decimal_t *res = decPackedToNumber((uint8_t *)*data, len, &scale, dec);
if (res) if (res)
*data += len; *data += len;
else else
(*data)--; *data = svp;
return res; return res;
} }
...@@ -91,7 +91,7 @@ char buf[32]; ...@@ -91,7 +91,7 @@ char buf[32];
static int static int
test_pack_unpack(void) test_pack_unpack(void)
{ {
plan(146); plan(151);
test_decpack("0"); test_decpack("0");
test_decpack("-0"); test_decpack("-0");
...@@ -112,13 +112,24 @@ test_pack_unpack(void) ...@@ -112,13 +112,24 @@ test_pack_unpack(void)
test_decpack("99999999999999999999999999999999999999"); test_decpack("99999999999999999999999999999999999999");
test_decpack("-99999999999999999999999999999999999999"); test_decpack("-99999999999999999999999999999999999999");
/* Check correct encoding of positive exponent numbers. */
decimal_t dec, d1;
decimal_from_string(&dec, "1e10");
uint32_t l1 = decimal_len(&dec);
ok(l1 == 2, "decimal_len() is small for positive exponent decimal");
char *b1 = decimal_pack(buf, &dec);
is(b1, buf + l1, "positive exponent decimal length");
const char *b2 = buf;
is(decimal_unpack(&b2, l1, &d1), &d1, "decimal_unpack() of a positive exponent decimal");
is(b1, b2, "decimal_unpack uses every byte packed by decimal_pack");
is(decimal_compare(&dec, &d1), 0, "positive exponent number is packed/unpacked correctly");
/* Pack an invalid decimal. */ /* Pack an invalid decimal. */
char *b = buf; char *b = buf;
*b++ = 1; *b++ = 1;
*b++ = '\xab'; *b++ = '\xab';
*b++ = '\xcd'; *b++ = '\xcd';
const char *bb = buf; const char *bb = buf;
decimal_t dec;
is(decimal_unpack(&bb, 3, &dec), NULL, "unpack malformed decimal fails"); is(decimal_unpack(&bb, 3, &dec), NULL, "unpack malformed decimal fails");
is(bb, buf, "decode malformed decimal preserves buffer position"); is(bb, buf, "decode malformed decimal preserves buffer position");
......
...@@ -277,7 +277,7 @@ ok 275 - decimal_from_string(-1) ...@@ -277,7 +277,7 @@ ok 275 - decimal_from_string(-1)
ok 276 - decimal_log10(-1) - error on wrong operands. ok 276 - decimal_log10(-1) - error on wrong operands.
ok 277 - decimal_from_string(-10) ok 277 - decimal_from_string(-10)
ok 278 - decimal_sqrt(-10) - error on wrong operands. ok 278 - decimal_sqrt(-10) - error on wrong operands.
1..146 1..151
ok 1 - decimal_len(0) ok 1 - decimal_len(0)
ok 2 - decimal_len(0) == len(decimal_pack(0) ok 2 - decimal_len(0) == len(decimal_pack(0)
ok 3 - decimal_unpack(decimal_pack(0)) ok 3 - decimal_unpack(decimal_pack(0))
...@@ -422,6 +422,11 @@ ok 278 - decimal_sqrt(-10) - error on wrong operands. ...@@ -422,6 +422,11 @@ ok 278 - decimal_sqrt(-10) - error on wrong operands.
ok 142 - decimal_unpack(decimal_pack(-99999999999999999999999999999999999999)) scale ok 142 - decimal_unpack(decimal_pack(-99999999999999999999999999999999999999)) scale
ok 143 - decimal_unpack(decimal_pack(-99999999999999999999999999999999999999)) precision ok 143 - decimal_unpack(decimal_pack(-99999999999999999999999999999999999999)) precision
ok 144 - str(decimal_unpack(decimal_pack(-99999999999999999999999999999999999999)) == -99999999999999999999999999999999999999 ok 144 - str(decimal_unpack(decimal_pack(-99999999999999999999999999999999999999)) == -99999999999999999999999999999999999999
ok 145 - unpack malformed decimal fails ok 145 - decimal_len() is small for positive exponent decimal
ok 146 - decode malformed decimal preserves buffer position ok 146 - positive exponent decimal length
ok 147 - decimal_unpack() of a positive exponent decimal
ok 148 - decimal_unpack uses every byte packed by decimal_pack
ok 149 - positive exponent number is packed/unpacked correctly
ok 150 - unpack malformed decimal fails
ok 151 - decode malformed decimal preserves buffer position
ok 279 - subtests ok 279 - subtests
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment