From d1df715971697107dc9fe0f8ffee2a3610bead1c Mon Sep 17 00:00:00 2001 From: leitner Date: Fri, 22 Aug 2003 15:03:10 +0000 Subject: [PATCH] add API for integer multiplication with overflow detection --- CHANGES | 1 + GNUmakefile | 14 ++++++++---- array.h | 33 +++++++++++++++++++++++++++ array/array_allocate.c | 51 ++++++++++++++++++++++++++++++++++++++++++ mult/imult16.c | 10 +++++++++ mult/imult32.c | 10 +++++++++ mult/imult64.c | 11 +++++++++ mult/umult16.c | 8 +++++++ mult/umult32.c | 8 +++++++ mult/umult64.c | 22 ++++++++++++++++++ safemult.h | 18 +++++++++++++++ uint16.h | 1 + uint32.h | 1 + 13 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 array.h create mode 100644 array/array_allocate.c create mode 100644 mult/imult16.c create mode 100644 mult/imult32.c create mode 100644 mult/imult64.c create mode 100644 mult/umult16.c create mode 100644 mult/umult32.c create mode 100644 mult/umult64.c create mode 100644 safemult.h diff --git a/CHANGES b/CHANGES index a57de4c..9302870 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,6 @@ 0.16: add buffer_fromsa (make buffer from stralloc) + add API for integer multiply with overflow detection 0.15: man page update (document stralloc return values) diff --git a/GNUmakefile b/GNUmakefile index fa17e22..7bcf902 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -10,7 +10,7 @@ INCLUDEDIR=${prefix}/include MAN3DIR=${prefix}/man/man3 LIBS=byte.a fmt.a scan.a str.a uint.a open.a stralloc.a unix.a socket.a \ -buffer.a mmap.a taia.a tai.a dns.a case.a +buffer.a mmap.a taia.a tai.a dns.a case.a mult.a all: t $(LIBS) libowfat.a @@ -22,7 +22,7 @@ CFLAGS=-I. -pipe -Wall -O2 -fomit-frame-pointer #CFLAGS=-pipe -Os -march=pentiumpro -mcpu=pentiumpro -fomit-frame-pointer -fschedule-insns2 -Wall # startrip -VPATH=str:byte:fmt:scan:uint:open:stralloc:unix:socket:buffer:mmap:textcode:taia:tai:dns:case +VPATH=str:byte:fmt:scan:uint:open:stralloc:unix:socket:buffer:mmap:textcode:taia:tai:dns:case:array:mult BYTE_OBJS=$(patsubst byte/%.c,%.o,$(wildcard byte/*.c)) FMT_OBJS=$(patsubst fmt/%.c,%.o,$(wildcard fmt/*.c)) @@ -40,6 +40,8 @@ TAI_OBJS=$(patsubst tai/%.c,%.o,$(wildcard tai/*.c)) TAIA_OBJS=$(patsubst taia/%.c,%.o,$(wildcard taia/*.c)) DNS_OBJS=$(patsubst dns/%.c,%.o,$(wildcard dns/*.c)) CASE_OBJS=$(patsubst case/%.c,%.o,$(wildcard case/*.c)) +ARRAY_OBJS=$(patsubst array/%.c,%.o,$(wildcard array/*.c)) +MULT_OBJS=$(patsubst mult/%.c,%.o,$(wildcard mult/*.c)) $(BYTE_OBJS): byte.h $(FMT_OBJS): fmt.h @@ -55,6 +57,8 @@ $(TAI_OBJS): tai.h uint64.h $(TAIA_OBJS): taia.h tai.h uint64.h $(DNS_OBJS): dns.h stralloc.h taia.h tai.h uint64.h iopause.h $(CASE_OBJS): case.h +$(ARRAY_OBJS): uint64.h array.h +$(MULT_OBJS): uint64.h uint32.h uint16.h safemult.h iopause.o: select.h openreadclose.o readclose.o: readclose.h @@ -77,11 +81,13 @@ taia.a: $(TAIA_OBJS) tai.a: $(TAI_OBJS) dns.a: $(DNS_OBJS) case.a: $(CASE_OBJS) +array.a: $(ARRAY_OBJS) +mult.a: $(MULT_OBJS) libowfat.a: $(DNS_OBJS) $(BYTE_OBJS) $(FMT_OBJS) $(SCAN_OBJS) \ $(STR_OBJS) $(UINT_OBJS) $(OPEN_OBJS) $(STRA_OBJS) $(UNIX_OBJS) \ $(SOCKET_OBJS) $(BUFFER_OBJS) $(MMAP_OBJS) $(TEXTCODE_OBJS) \ -$(TAIA_OBJS) $(TAI_OBJS) $(CASE_OBJS) +$(TAIA_OBJS) $(TAI_OBJS) $(CASE_OBJS) $(ARRAY_OBJS) $(MULT_OBJS) %.o: %.c $(DIET) $(CC) -c $< -o $@ $(CFLAGS) @@ -102,7 +108,7 @@ iopause.h select.h Makefile INCLUDES=buffer.h byte.h fmt.h ip4.h ip6.h mmap.h scan.h socket.h str.h stralloc.h \ uint16.h uint32.h uint64.h open.h textcode.h tai.h taia.h dns.h iopause.h case.h \ -openreadclose.h readclose.h ndelay.h +openreadclose.h readclose.h ndelay.h array.h io.h safemult.h install: libowfat.a install -d $(INCLUDEDIR) $(MAN3DIR) $(LIBDIR) diff --git a/array.h b/array.h new file mode 100644 index 0000000..4d5d966 --- /dev/null +++ b/array.h @@ -0,0 +1,33 @@ +#ifndef _ARRAY_H +#define _ARRAY_H + +#include "uint64.h" +#include + +typedef struct { + char* p; + int64 allocated, initialized; /* in bytes */ + + /* p and allocated nonzero: array is allocated */ + /* p zero: array is unallocated */ + /* allocated < 0: array is failed */ +} array; + +void* array_allocate(array* x,int64 membersize,int64 pos); +void* array_get(array* x,int64 membersize,int64 pos); +void* array_start(const array* const x); +int64 array_length(const array* const x,int64 membersize); +int64 array_bytes(const array* const x); +void array_truncate(array* x,int64 membersize,int64 len); +void array_trunc(array* x); +void array_reset(array* x); +void array_fail(array* x); +int array_equal(const array* const x,const array* const y); +void array_cat(array* to,const array* const from); +void array_catb(array* to,const char* from,int64 len); +void array_cats(array* to,const char* from); +void array_cats0(array* to,const char* from); +void array_cat0(array* to); +void array_cate(array* to,const array* const from,int64 pos,int64 stop); + +#endif diff --git a/array/array_allocate.c b/array/array_allocate.c new file mode 100644 index 0000000..7b18cc5 --- /dev/null +++ b/array/array_allocate.c @@ -0,0 +1,51 @@ +#include "array.h" + +#if 0 + static array x; + t *p; + int64 pos; + + p = array_allocate(&x,sizeof(t),pos); + + array_allocate makes sure that enough bytes are allocated in x for at + least pos+1 objects of type t. (The size of t must be positive; + otherwise the effects are undefined.) If not enough bytes are + allocated (or x is unallocated), array_allocate allocates more bytes, + moving the dynamically allocated region if necessary. array_allocate + often allocates somewhat more bytes than necessary, to save time + later. + + array_allocate then makes sure that the number of bytes initialized + covers at least those pos+1 objects. If not enough bytes are + initialized, array_allocate initializes more bytes (setting them to + 0), up to exactly the end of the pos+1st object. + + array_allocate then returns a pointer to the pos+1st object; i.e., + object number pos, with objects numbered starting at 0. This pointer + can be used to change or inspect the object. The pointer can continue + to be used through subsequent calls to array_get, array_start, + array_length, and array_bytes, but it must not be used after any + other operations on this array. + + If something goes wrong, array_allocate returns 0, setting errno + appropriately, without touching x. In particular, array_allocate + returns 0 if + + * x has failed, or + * pos is negative, or + * not enough memory is available. + + array_allocate does not change x to have failed; if you want to do + that, use array_fail. +#endif + +void* array_allocate(array* x,int64 membersize,int64 pos) { + int64 wanted; + if (membersize<128) + wanted=(pos+127)&(-128ll); /* round up to multiple of 128 */ + else + wanted=(pos+4095)&(-4096ll); /* round up to 4k pages */ + /* detect numeric overflow */ + if (wanted<0) return 0; + wanted=membersize*(pos+1); +} diff --git a/mult/imult16.c b/mult/imult16.c new file mode 100644 index 0000000..45bc8b9 --- /dev/null +++ b/mult/imult16.c @@ -0,0 +1,10 @@ +#include "safemult.h" + +int imult16(int16 a,int16 b,int16* c) { + int neg=(a<0); + if (neg) a=-a; + if (b<0) { neg^=1; b=-b; } + if (umult16(a,b,c)) return 1; + if (neg) *c=-*c; + return 0; +} diff --git a/mult/imult32.c b/mult/imult32.c new file mode 100644 index 0000000..044fabb --- /dev/null +++ b/mult/imult32.c @@ -0,0 +1,10 @@ +#include "safemult.h" + +int imult32(int32 a,int32 b,int32* c) { + int neg=(a<0); + if (neg) a=-a; + if (b<0) { neg^=1; b=-b; } + if (umult32(a,b,c)) return 1; + if (neg) *c=-*c; + return 0; +} diff --git a/mult/imult64.c b/mult/imult64.c new file mode 100644 index 0000000..c227aad --- /dev/null +++ b/mult/imult64.c @@ -0,0 +1,11 @@ +#include "safemult.h" + +int imult64(int64 a,int64 b,int64* c) { + int neg=(a<0); + if (neg) a=-a; + if (b<0) { neg^=1; b=-b; } + if (umult64(a,b,c)) return 1; + if (neg) *c=-*c; + return 0; +} + diff --git a/mult/umult16.c b/mult/umult16.c new file mode 100644 index 0000000..879ffe5 --- /dev/null +++ b/mult/umult16.c @@ -0,0 +1,8 @@ +#include "safemult.h" + +int umult16(uint16 a,uint16 b,uint16* c) { + unsigned long x=(unsigned long)a*b; + if (x>0xffff) return 1; + *c=x&0xffff; + return 0; +} diff --git a/mult/umult32.c b/mult/umult32.c new file mode 100644 index 0000000..ba04ed7 --- /dev/null +++ b/mult/umult32.c @@ -0,0 +1,8 @@ +#include "safemult.h" + +int umult32(uint32 a,uint32 b,uint32* c) { + unsigned long long x=(unsigned long long)a*b; + if (x>0xffffffff) return 1; + *c=x&0xffffffff; + return 0; +} diff --git a/mult/umult64.c b/mult/umult64.c new file mode 100644 index 0000000..a72d1ca --- /dev/null +++ b/mult/umult64.c @@ -0,0 +1,22 @@ +#include "safemult.h" + +/* return 1 for overflow, 0 for ok */ +int umult64(uint64 a,uint64 b,uint64* c) { + uint32 ahi=a>>32; + uint32 alo=(a&0xffffffff); + uint32 bhi=b>>32; + uint32 blo=(b&0xffffffff); + + // a=ahi*x+alo, b=bhi*x+blo + // a*b = (ahi*x+alo) * (bhi*x+blo) + // = ahi*x*bhi*x + ahi*x*blo + alo*bhi*x + alo*blo + + // -> overflow if ahi*bhi != zero */ + if (ahi && bhi) return 1; + + a=(uint64)(ahi)*blo+(uint64)(alo)*bhi; + if (a>0xffffffff) return 1; + *c=(a<<32)+(uint64)(alo)*blo; + return 0; +} + diff --git a/safemult.h b/safemult.h new file mode 100644 index 0000000..a1194a4 --- /dev/null +++ b/safemult.h @@ -0,0 +1,18 @@ +#ifndef _SAFEMULT_H +#define _SAFEMULT_H + +#include "uint16.h" +#include "uint32.h" +#include "uint64.h" + +/* return 1 for overflow, 0 for ok */ +int umult16(uint16 a,uint16 b,uint16* c); +int imult16( int16 a, int16 b, int16* c); + +int umult32(uint32 a,uint32 b,uint32* c); +int imult32( int32 a, int32 b, int32* c); + +int umult64(uint64 a,uint64 b,uint64* c); +int imult64( int64 a, int64 b, int64* c); + +#endif diff --git a/uint16.h b/uint16.h index e52f4c9..b1757ac 100644 --- a/uint16.h +++ b/uint16.h @@ -2,6 +2,7 @@ #define UINT16_H typedef unsigned short uint16; +typedef signed short int16; #if defined(__i386__) && !defined(NO_UINT16_MACROS) #define uint16_pack(out,in) (*(uint16*)(out)=(in)) diff --git a/uint32.h b/uint32.h index 004b88d..2b46eab 100644 --- a/uint32.h +++ b/uint32.h @@ -2,6 +2,7 @@ #define UINT32_H typedef unsigned int uint32; +typedef signed int int32; #if defined(__i386__) && !defined(NO_UINT32_MACROS) #define uint32_pack(out,in) (*(uint32*)(out)=(in))