OER support and randomized testing for the REAL (floating point) type

This commit is contained in:
Lev Walkin 2017-10-03 18:43:12 -07:00
parent 68619bf6ef
commit ab1d1e1ea4
7 changed files with 285 additions and 108 deletions

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2004, 2006 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
/*
@ -51,8 +51,8 @@ asn_TYPE_operation_t asn_OP_NativeReal = {
0,
0,
#else
0,
0,
NativeReal_decode_oer,
NativeReal_encode_oer,
#endif /* ASN_DISABLE_OER_SUPPORT */
#ifdef ASN_DISABLE_PER_SUPPORT
0,
@ -82,111 +82,93 @@ asn_TYPE_descriptor_t asn_DEF_NativeReal = {
*/
asn_dec_rval_t
NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
asn_TYPE_descriptor_t *td,
void **dbl_ptr, const void *buf_ptr, size_t size, int tag_mode) {
double *Dbl = (double *)*dbl_ptr;
asn_dec_rval_t rval;
ber_tlv_len_t length;
asn_TYPE_descriptor_t *td, void **dbl_ptr,
const void *buf_ptr, size_t size, int tag_mode) {
double *Dbl = (double *)*dbl_ptr;
asn_dec_rval_t rval;
ber_tlv_len_t length;
/*
* If the structure is not there, allocate it.
*/
if(Dbl == NULL) {
*dbl_ptr = CALLOC(1, sizeof(*Dbl));
Dbl = (double *)*dbl_ptr;
if(Dbl == NULL) {
rval.code = RC_FAIL;
rval.consumed = 0;
return rval;
}
}
/*
* If the structure is not there, allocate it.
*/
if(Dbl == NULL) {
*dbl_ptr = CALLOC(1, sizeof(*Dbl));
Dbl = (double *)*dbl_ptr;
if(Dbl == NULL) {
rval.code = RC_FAIL;
rval.consumed = 0;
return rval;
}
}
ASN_DEBUG("Decoding %s as REAL (tm=%d)",
td->name, tag_mode);
ASN_DEBUG("Decoding %s as REAL (tm=%d)", td->name, tag_mode);
/*
* Check tags.
*/
rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size,
tag_mode, 0, &length, 0);
if(rval.code != RC_OK)
return rval;
/*
* Check tags.
*/
rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, tag_mode, 0,
&length, 0);
if(rval.code != RC_OK) return rval;
ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
/*
* Make sure we have this length.
*/
buf_ptr = ((const char *)buf_ptr) + rval.consumed;
size -= rval.consumed;
if(length > (ber_tlv_len_t)size) {
rval.code = RC_WMORE;
rval.consumed = 0;
return rval;
}
/*
* Make sure we have this length.
*/
buf_ptr = ((const char *)buf_ptr) + rval.consumed;
size -= rval.consumed;
if(length > (ber_tlv_len_t)size) {
rval.code = RC_WMORE;
rval.consumed = 0;
return rval;
}
/*
* ASN.1 encoded REAL: buf_ptr, length
* Fill the Dbl, at the same time checking for overflow.
* If overflow occured, return with RC_FAIL.
*/
{
REAL_t tmp;
union {
const void *constbuf;
void *nonconstbuf;
} unconst_buf;
double d;
/*
* ASN.1 encoded REAL: buf_ptr, length
* Fill the Dbl, at the same time checking for overflow.
* If overflow occured, return with RC_FAIL.
*/
{
uint8_t scratch[24]; /* Longer than %.16f in decimal */
REAL_t tmp;
double d;
int ret;
unconst_buf.constbuf = buf_ptr;
tmp.buf = (uint8_t *)unconst_buf.nonconstbuf;
tmp.size = length;
if(length < sizeof(scratch)) {
tmp.buf = scratch;
tmp.size = length;
} else {
/* This rarely happens: impractically long value */
tmp.buf = CALLOC(1, length + 1);
tmp.size = length;
if(!tmp.buf) {
rval.code = RC_FAIL;
rval.consumed = 0;
return rval;
}
}
if(length < (ber_tlv_len_t)size) {
int ret;
uint8_t saved_byte = tmp.buf[tmp.size];
tmp.buf[tmp.size] = '\0';
ret = asn_REAL2double(&tmp, &d);
tmp.buf[tmp.size] = saved_byte;
if(ret) {
rval.code = RC_FAIL;
rval.consumed = 0;
return rval;
}
} else if(length < 48 /* Enough for longish %f value. */) {
tmp.buf = alloca(length + 1);
tmp.size = length;
memcpy(tmp.buf, buf_ptr, length);
tmp.buf[tmp.size] = '\0';
if(asn_REAL2double(&tmp, &d)) {
rval.code = RC_FAIL;
rval.consumed = 0;
return rval;
}
} else {
/* This should probably never happen: impractically long value */
tmp.buf = CALLOC(1, length + 1);
tmp.size = length;
if(tmp.buf) memcpy(tmp.buf, buf_ptr, length);
if(!tmp.buf || asn_REAL2double(&tmp, &d)) {
FREEMEM(tmp.buf);
rval.code = RC_FAIL;
rval.consumed = 0;
return rval;
}
FREEMEM(tmp.buf);
}
memcpy(tmp.buf, buf_ptr, length);
tmp.buf[length] = '\0';
*Dbl = d;
}
ret = asn_REAL2double(&tmp, &d);
if(tmp.buf != scratch) FREEMEM(tmp.buf);
if(ret) {
rval.code = RC_FAIL;
rval.consumed = 0;
return rval;
}
rval.code = RC_OK;
rval.consumed += length;
*Dbl = d;
}
ASN_DEBUG("Took %ld/%ld bytes to encode %s (%f)",
(long)rval.consumed, (long)length, td->name, *Dbl);
rval.code = RC_OK;
rval.consumed += length;
return rval;
ASN_DEBUG("Took %ld/%ld bytes to encode %s (%f)", (long)rval.consumed,
(long)length, td->name, *Dbl);
return rval;
}
/*
@ -298,6 +280,107 @@ NativeReal_encode_uper(asn_TYPE_descriptor_t *td,
#endif /* ASN_DISABLE_PER_SUPPORT */
#ifndef ASN_DISABLE_OER_SUPPORT
/*
* Encode as Canonical OER.
*/
asn_enc_rval_t
NativeReal_encode_oer(asn_TYPE_descriptor_t *td,
const asn_oer_constraints_t *constraints, void *sptr,
asn_app_consume_bytes_f *cb, void *app_key) {
asn_enc_rval_t er = { 0, 0, 0 };
ssize_t len_len;
const double *d = sptr;
REAL_t tmp;
/* Prepare a temporary clean structure */
memset(&tmp, 0, sizeof(tmp));
(void)td;
(void)constraints; /* Constraints are unused in OER */
if(asn_double2REAL(&tmp, *d)) {
ASN__ENCODE_FAILED;
}
/* Encode a fake REAL */
len_len = oer_serialize_length(tmp.size, cb, app_key);
if(len_len < 0 || cb(tmp.buf, tmp.size, app_key) < 0) {
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
ASN__ENCODE_FAILED;
} else {
er.encoded = len_len + tmp.size;
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
ASN__ENCODED_OK(er);
}
}
asn_dec_rval_t
NativeReal_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
asn_TYPE_descriptor_t *td,
const asn_oer_constraints_t *constraints, void **sptr,
const void *ptr, size_t size) {
asn_dec_rval_t ok = {RC_OK, 0};
double *st;
double d;
ssize_t len_len;
size_t real_body_len;
(void)opt_codec_ctx;
(void)td;
(void)constraints; /* Constraints are unused in OER */
len_len = oer_fetch_length(ptr, size, &real_body_len);
if(len_len < 0) ASN__DECODE_FAILED;
if(len_len == 0) ASN__DECODE_STARVED;
ptr = (const char *)ptr + len_len;
size -= len_len;
if(real_body_len > size) ASN__DECODE_STARVED;
{
uint8_t scratch[24]; /* Longer than %.16f in decimal */
REAL_t tmp;
int ret;
if(real_body_len < sizeof(scratch)) {
tmp.buf = scratch;
tmp.size = real_body_len;
} else {
/* This rarely happens: impractically long value */
tmp.buf = CALLOC(1, real_body_len + 1);
tmp.size = real_body_len;
if(!tmp.buf) {
ASN__DECODE_FAILED;
}
}
memcpy(tmp.buf, ptr, real_body_len);
tmp.buf[real_body_len] = '\0';
ret = asn_REAL2double(&tmp, &d);
if(tmp.buf != scratch) FREEMEM(tmp.buf);
if(ret) {
ASN_DEBUG("REAL decoded in %zu bytes, but can't convert t double",
real_body_len);
ASN__DECODE_FAILED;
}
}
if(!(st = *sptr)) {
st = (double *)(*sptr = CALLOC(1, sizeof(*st)));
if(!st) ASN__DECODE_FAILED;
}
*st = d;
ok.consumed = len_len + real_body_len;
return ok;
}
#endif /* ASN_DISABLE_OER_SUPPORT */
/*
* Decode the chunk of XML text encoding REAL.
*/
@ -426,10 +509,18 @@ asn_random_fill_result_t
NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
const asn_encoding_constraints_t *constraints,
size_t max_length) {
asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
asn_random_fill_result_t result_ok = {ARFILL_OK, sizeof(double)};
asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
static const double values[] = {0, -0.0, -1, 1, INFINITY, -INFINITY, NAN};
static const double values[] = {
0, -0.0, -1, 1, -M_E, M_E, -3.14, 3.14, -M_PI, M_PI, -255, 255,
/* 2^51 */
-2251799813685248.0, 2251799813685248.0,
/* 2^52 */
-4503599627370496.0, 4503599627370496.0,
/* 2^100 */
-1267650600228229401496703205376.0, 1267650600228229401496703205376.0,
-MAXFLOAT, MAXFLOAT, INFINITY, -INFINITY, NAN};
double *st;
double d;
@ -451,6 +542,5 @@ NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
*st = d;
result_ok.length = sizeof(double);
return result_ok;
}

View File

@ -25,10 +25,12 @@ asn_struct_print_f NativeReal_print;
asn_struct_compare_f NativeReal_compare;
ber_type_decoder_f NativeReal_decode_ber;
der_type_encoder_f NativeReal_encode_der;
xer_type_decoder_f NativeReal_decode_xer;
xer_type_encoder_f NativeReal_encode_xer;
per_type_decoder_f NativeReal_decode_uper;
per_type_encoder_f NativeReal_encode_uper;
oer_type_decoder_f NativeReal_decode_oer;
oer_type_encoder_f NativeReal_encode_oer;
xer_type_decoder_f NativeReal_decode_xer;
xer_type_encoder_f NativeReal_encode_xer;
asn_random_fill_f NativeReal_random_fill;
#define NativeReal_constraint asn_generic_no_constraint

View File

@ -127,7 +127,7 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key)
char local_buf[64];
char *buf = local_buf;
ssize_t buflen = sizeof(local_buf);
const char *fmt = canonical?"%.15E":"%.15f";
const char *fmt = canonical ? "%.17E" /* Precise */ : "%.15f" /* Pleasant*/;
ssize_t ret;
/*
@ -522,7 +522,6 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
return -1;
}
/* 1. By contract, an input buffer should be '\0'-terminated.
* OCTET STRING decoder ensures that, as is asn_double2REAL().
* 2. ISO 6093 specifies COMMA as a possible decimal separator.
@ -574,7 +573,7 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
*/
{
double m;
int expval; /* exponent value */
int32_t expval; /* exponent value */
unsigned int elen; /* exponent value length, in octets */
int scaleF;
int baseF;
@ -615,6 +614,10 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
/* Fetch the multibyte exponent */
expval = (int)(*(int8_t *)ptr);
if(elen >= sizeof(expval)-1) {
errno = ERANGE;
return -1;
}
end = ptr + elen + 1;
for(ptr++; ptr < end; ptr++)
expval = (expval * 256) + *ptr;
@ -627,8 +630,8 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
m = ldexp(m, 8) + *ptr;
if(0)
ASN_DEBUG("m=%.10f, scF=%d, bF=%d, expval=%d, ldexp()=%f, ldexp()=%f\n",
m, scaleF, baseF, expval,
ASN_DEBUG("m=%.10f [%08llx], scF=%d, bF=%d, expval=%d, ldexp()=%f, ldexp()=%f\n",
m, *(uint64_t*)&m, scaleF, baseF, expval,
ldexp(m, expval * baseF + scaleF),
ldexp(m, scaleF) * pow(pow(2, baseF), expval)
);
@ -636,7 +639,7 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
/*
* (S * N * 2^F) * B^E
* Essentially:
m = ldexp(m, scaleF) * pow(pow(2, base), expval);
m = ldexp(m, scaleF) * pow(pow(2, baseF), expval);
*/
m = ldexp(m, expval * baseF + scaleF);
if(asn_isfinite(m)) {
@ -856,7 +859,15 @@ REAL_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
static const double values[] = {0, -0.0, -1, 1, INFINITY, -INFINITY, NAN};
static const double values[] = {
0, -0.0, -1, 1, -M_E, M_E, -3.14, 3.14, -M_PI, M_PI, -255, 255,
/* 2^51 */
-2251799813685248.0, 2251799813685248.0,
/* 2^52 */
-4503599627370496.0, 4503599627370496.0,
/* 2^100 */
-1267650600228229401496703205376.0, 1267650600228229401496703205376.0,
-MAXFLOAT, MAXFLOAT, INFINITY, -INFINITY, NAN};
REAL_t *st;
double d;
@ -887,3 +898,4 @@ REAL_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
result_ok.length = st->size;
return result_ok;
}

View File

@ -0,0 +1,2 @@
-- Test the REAL (floating point) type.
T ::= REAL

View File

@ -0,0 +1,25 @@
-- Test encoding/decoding/transcoding of everything concerning the BIT STRING.
T ::= BIT STRING { foo(0) }
T ::= BIT STRING { foo(0) } (SIZE(0..1))
T ::= BIT STRING { foo(0) } (SIZE(1))
T ::= BIT STRING { foo(0) } (SIZE(1..MAX))
T ::= BIT STRING { foo(0) } (SIZE(1..2))
T ::= BIT STRING { foo(0) } (SIZE(2))
T ::= BIT STRING { foo(0) } (SIZE(2,...))
T ::= BIT STRING { foo(0), bar(65535) }
T ::= BIT STRING { foo(0), bar(65535) } (SIZE(0..16))
T ::= BIT STRING { foo(0), bar(65535) } (SIZE(16))
T ::= BIT STRING { foo(0), bar(2147483647) }
T ::= BIT STRING { foo(0), bar(2147483647) } (SIZE(1..MAX))
T ::= BIT STRING { foo(2147483648), bar(0), baz(2147483647) }
T ::= BIT STRING { foo(2147483648), baz(2147483647) }
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(32))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(31,...))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..32))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..31,...))
T ::= BIT STRING { foo(0) } (SIZE(65535)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65536)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65537)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65535,...)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65536,...)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65537,...)) -- RMAX=65540

View File

@ -0,0 +1,19 @@
-- Test encoding/decoding/transcoding of a primitive byte string type
T ::= OCTET STRING
T ::= OCTET STRING ("Value Constraint")
T ::= OCTET STRING (SIZE(0))
T ::= OCTET STRING (SIZE(0,...))
T ::= OCTET STRING (SIZE(1))
T ::= OCTET STRING (SIZE(1,...))
T ::= OCTET STRING (SIZE(2))
T ::= OCTET STRING (SIZE(2,...))
T ::= OCTET STRING (SIZE(1..2))
T ::= OCTET STRING (SIZE(1..2,...))
T ::= OCTET STRING (SIZE(1..127))
T ::= OCTET STRING (SIZE(1..128))
T ::= OCTET STRING (SIZE(1..129))
T ::= OCTET STRING (SIZE(64000)) -- RMAX=64000, #11.9.3.3
T ::= OCTET STRING (SIZE(32000..32002)) -- RMAX=33000
T ::= OCTET STRING (SIZE(65530..65535)) -- RMAX=65536
T ::= OCTET STRING (SIZE(65530..65536)) -- RMAX=65536
T ::= OCTET STRING (SIZE(65535..65550)) -- RMAX=66000

View File

@ -0,0 +1,27 @@
-- Test encoding/decoding/transcoding of a simple string type
T ::= VisibleString
T ::= VisibleString ("Value Constraint")
T ::= VisibleString (SIZE(0))
T ::= VisibleString (SIZE(0,...))
T ::= VisibleString (SIZE(1))
T ::= VisibleString (SIZE(1)) (FROM("A".."B"))
T ::= VisibleString (SIZE(1,...))
T ::= VisibleString (SIZE(2))
T ::= VisibleString (SIZE(2,...))
T ::= VisibleString (SIZE(1..2))
T ::= VisibleString (SIZE(1..2,...))
T ::= VisibleString (SIZE(4..6,...)) (FROM("A".."B"))
T ::= VisibleString (SIZE(1..MAX)) (FROM("A".."B"))
T ::= VisibleString (SIZE(1..127))
T ::= VisibleString (SIZE(1..128))
T ::= VisibleString (SIZE(1..129))
T ::= VisibleString (SIZE(5) INTERSECTION FROM("A".."Z"))
T ::= VisibleString (SIZE(4..6) INTERSECTION (FROM("A".."B")))
T ::= VisibleString (SIZE(4..6,...) INTERSECTION (FROM("A".."B")))
T ::= VisibleString (SIZE(64000)) -- RMAX=64000, #11.9.3.3
T ::= VisibleString (SIZE(32000..32002)) -- RMAX=33000
T ::= VisibleString (SIZE(32000..32002)) (FROM("A".."B")) -- RMAX=33000
T ::= VisibleString (SIZE(32000..32002,...)) (FROM("A".."B")) -- RMAX=33000
T ::= VisibleString (SIZE(65530..65535)) -- RMAX=65536
T ::= VisibleString (SIZE(65530..65536)) -- RMAX=65536
T ::= VisibleString (SIZE(65535..65550)) -- RMAX=66000