add API for integer multiplication with overflow detection

master
leitner 22 years ago
parent ccc0a23183
commit d1df715971

@ -1,5 +1,6 @@
0.16: 0.16:
add buffer_fromsa (make buffer from stralloc) add buffer_fromsa (make buffer from stralloc)
add API for integer multiply with overflow detection
0.15: 0.15:
man page update (document stralloc return values) man page update (document stralloc return values)

@ -10,7 +10,7 @@ INCLUDEDIR=${prefix}/include
MAN3DIR=${prefix}/man/man3 MAN3DIR=${prefix}/man/man3
LIBS=byte.a fmt.a scan.a str.a uint.a open.a stralloc.a unix.a socket.a \ 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 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 #CFLAGS=-pipe -Os -march=pentiumpro -mcpu=pentiumpro -fomit-frame-pointer -fschedule-insns2 -Wall
# startrip # 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)) BYTE_OBJS=$(patsubst byte/%.c,%.o,$(wildcard byte/*.c))
FMT_OBJS=$(patsubst fmt/%.c,%.o,$(wildcard fmt/*.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)) TAIA_OBJS=$(patsubst taia/%.c,%.o,$(wildcard taia/*.c))
DNS_OBJS=$(patsubst dns/%.c,%.o,$(wildcard dns/*.c)) DNS_OBJS=$(patsubst dns/%.c,%.o,$(wildcard dns/*.c))
CASE_OBJS=$(patsubst case/%.c,%.o,$(wildcard case/*.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 $(BYTE_OBJS): byte.h
$(FMT_OBJS): fmt.h $(FMT_OBJS): fmt.h
@ -55,6 +57,8 @@ $(TAI_OBJS): tai.h uint64.h
$(TAIA_OBJS): taia.h 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 $(DNS_OBJS): dns.h stralloc.h taia.h tai.h uint64.h iopause.h
$(CASE_OBJS): case.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 iopause.o: select.h
openreadclose.o readclose.o: readclose.h openreadclose.o readclose.o: readclose.h
@ -77,11 +81,13 @@ taia.a: $(TAIA_OBJS)
tai.a: $(TAI_OBJS) tai.a: $(TAI_OBJS)
dns.a: $(DNS_OBJS) dns.a: $(DNS_OBJS)
case.a: $(CASE_OBJS) case.a: $(CASE_OBJS)
array.a: $(ARRAY_OBJS)
mult.a: $(MULT_OBJS)
libowfat.a: $(DNS_OBJS) $(BYTE_OBJS) $(FMT_OBJS) $(SCAN_OBJS) \ libowfat.a: $(DNS_OBJS) $(BYTE_OBJS) $(FMT_OBJS) $(SCAN_OBJS) \
$(STR_OBJS) $(UINT_OBJS) $(OPEN_OBJS) $(STRA_OBJS) $(UNIX_OBJS) \ $(STR_OBJS) $(UINT_OBJS) $(OPEN_OBJS) $(STRA_OBJS) $(UNIX_OBJS) \
$(SOCKET_OBJS) $(BUFFER_OBJS) $(MMAP_OBJS) $(TEXTCODE_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 %.o: %.c
$(DIET) $(CC) -c $< -o $@ $(CFLAGS) $(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 \ 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 \ 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: libowfat.a
install -d $(INCLUDEDIR) $(MAN3DIR) $(LIBDIR) install -d $(INCLUDEDIR) $(MAN3DIR) $(LIBDIR)

@ -0,0 +1,33 @@
#ifndef _ARRAY_H
#define _ARRAY_H
#include "uint64.h"
#include <errno.h>
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

@ -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);
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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

@ -2,6 +2,7 @@
#define UINT16_H #define UINT16_H
typedef unsigned short uint16; typedef unsigned short uint16;
typedef signed short int16;
#if defined(__i386__) && !defined(NO_UINT16_MACROS) #if defined(__i386__) && !defined(NO_UINT16_MACROS)
#define uint16_pack(out,in) (*(uint16*)(out)=(in)) #define uint16_pack(out,in) (*(uint16*)(out)=(in))

@ -2,6 +2,7 @@
#define UINT32_H #define UINT32_H
typedef unsigned int uint32; typedef unsigned int uint32;
typedef signed int int32;
#if defined(__i386__) && !defined(NO_UINT32_MACROS) #if defined(__i386__) && !defined(NO_UINT32_MACROS)
#define uint32_pack(out,in) (*(uint32*)(out)=(in)) #define uint32_pack(out,in) (*(uint32*)(out)=(in))

Loading…
Cancel
Save