From ea4538231ed96b8deac3e3e86f46b8c292137131 Mon Sep 17 00:00:00 2001 From: Avril Date: Fri, 1 Oct 2021 13:53:48 +0100 Subject: [PATCH] Fix incorrect uint48_t sizing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve xsubi via ifunc if bitfield is placed in unexpected location within union. Fortune for cpprng's current commit: Middle blessing − 中吉 --- include/common.h | 1 - include/rng/crand.h | 3 -- src/rng/crand.c | 80 +++++++++++++++++++++++++++++++++++++++++---- src/rng/crand.cpp | 8 ++--- src/rng/crand.h | 4 +-- 5 files changed, 80 insertions(+), 16 deletions(-) diff --git a/include/common.h b/include/common.h index a78773e..cc80bd8 100644 --- a/include/common.h +++ b/include/common.h @@ -9,7 +9,6 @@ extern "C" { #include #include - #define DEF(s, n) typedef s ## int ## n ## _t s ## n #define DEFINT(n) typedef uint ## n ## _t u ## n; \ typedef int ## n ## _t i ## n diff --git a/include/rng/crand.h b/include/rng/crand.h index f099b67..50ce02f 100644 --- a/include/rng/crand.h +++ b/include/rng/crand.h @@ -9,8 +9,5 @@ namespace rng { private: - struct _inner; - // XXX: FUCK: This doesn't fucking work... - mem::aligned_ptr _state; }; } diff --git a/src/rng/crand.c b/src/rng/crand.c index f76a31a..183d1b1 100644 --- a/src/rng/crand.c +++ b/src/rng/crand.c @@ -1,8 +1,14 @@ #include #include +#include +#include +#include #include "crand.h" +typedef unsigned short uint48_t[3]; + + struct jr_state { long result; @@ -10,22 +16,46 @@ struct jr_state union { unsigned short xsubi[3]; struct { - unsigned int xsubh : 24; - unsigned char _xsub : 8; + uint64_t xsubh : 48; + uint16_t _xsub : 16; }; - unsigned int xsubl; + uint64_t xsubl; } st; }; +_Static_assert( sizeof(uint48_t) == (sizeof(uint16_t) * 3), "bad uint48 (ushort[3])"); +_Static_assert( sizeof(((struct jr_state*)NULL)->st) == sizeof(uint64_t), "bad uint64 (union st)"); + +static unsigned short* _impl__jr_st_resolv__low(struct jr_state* restrict state) +{ + return state->st.xsubi; +} -void _jr_seed(struct jr_state* restrict state, unsigned int with) +static unsigned short* _impl__jr_st_resolv__high(struct jr_state* restrict state) +{ + return state->st.xsubi+1; +} + +static unsigned short* (*_ifun__jr_st_resolv (void)) (struct jr_state* restrict state) +{ + struct jr_state chk = {0}; + chk.st.xsubh = JR_MAX; + return chk.st._xsub + ? &_impl__jr_st_resolv__high + : &_impl__jr_st_resolv__low; +} + +static unsigned short* _jr_st_resolv(struct jr_state* restrict state) + __attribute__((ifunc("_ifun__jr_st_resolv"))); + +void _jr_seed(struct jr_state* restrict state, unsigned long with) { state->st.xsubh = with; - seed48_r(state->st.xsubi, &state->data); + seed48_r(_jr_st_resolv(state), &state->data); } long _jr_proc(struct jr_state* restrict state) { - jrand48_r(state->st.xsubi, &state->data, &state->result); + jrand48_r(_jr_st_resolv(state), &state->data, &state->result); return state->result; } @@ -41,3 +71,41 @@ void _jr_free(struct jr_state* restrict state) { free(state); } + +//TODO: Use test macros from tracemac, run with attr(ctor) if `-DTEST` is provided. +void __TEST__jr_test() +{ + struct jr_state* st = _jr_alloc(); + assert(!st->st._xsub); + _jr_seed(st, ~0UL); + const volatile unsigned short* res_state = _jr_st_resolv(st); + printf("seeded: %lu (full %lu, spill %u). xsubi = [%04x, %04x, %04x) %04x], resolv = [%04x, %04x, %04x) %04x]\n", (uint64_t)st->st.xsubh, st->st.xsubl, st->st._xsub, + st->st.xsubi[0], + st->st.xsubi[1], + st->st.xsubi[2], + st->st.xsubi[3], + + res_state[0], + res_state[1], + res_state[2], + res_state[3]); + assert(!st->st._xsub); + for(int i=0;i<10;i++) + { + printf("res: %ld\n", _jr_proc(st)); + printf("state: %lu (full %lu, spill %u). xsubi = %p, resolv = %p\n", (uint64_t)st->st.xsubh, st->st.xsubl, st->st._xsub, + (const void*)st->st.xsubi, (const void*)_jr_st_resolv(st)); + } + printf("ended: %lu (full %lu, spill %u). xsubi = [%04x, %04x, %04x) %04x], resolv = [%04x, %04x, %04x) %04x]\n", (uint64_t)st->st.xsubh, st->st.xsubl, st->st._xsub, + st->st.xsubi[0], + st->st.xsubi[1], + st->st.xsubi[2], + st->st.xsubi[3], + + res_state[0], + res_state[1], + res_state[2], + res_state[3]); + assert(!st->st._xsub); + _jr_free(st); +} diff --git a/src/rng/crand.cpp b/src/rng/crand.cpp index a206620..d0040da 100644 --- a/src/rng/crand.cpp +++ b/src/rng/crand.cpp @@ -6,10 +6,10 @@ namespace rng { - struct crand::_inner { - - jr_state st; - }; + //struct crand::_inner { + // + // jr_state st; + //}; //TODO: Make header for rng::crand, a derived type of `Random`. } diff --git a/src/rng/crand.h b/src/rng/crand.h index 3bcb130..18d2dc2 100644 --- a/src/rng/crand.h +++ b/src/rng/crand.h @@ -3,7 +3,7 @@ #include -#define JR_MAX (UINT32_MAX >> 8) +#define JR_MAX (UINT64_MAX >> 16) #ifdef __cplusplus extern "C" { @@ -13,7 +13,7 @@ struct jr_state; //TODO: make all these functions visibility("internal") -void _jr_seed(struct jr_state* restrict state, unsigned int with); +void _jr_seed(struct jr_state* restrict state, unsigned long with); long _jr_proc(struct jr_state* restrict state); struct jr_state* _jr_alloc(); void _jr_free(struct jr_state* restrict state);