diff --git a/cmdline.c b/cmdline.c index 083231f1..06f1520f 100644 --- a/cmdline.c +++ b/cmdline.c @@ -35,7 +35,7 @@ struct cmdline_saved_param { }; struct cmdline_saved_param_set { struct cmdline_saved_param *params; - int nsaved, savesize; + size_t nsaved, savesize; }; /* @@ -46,11 +46,7 @@ static struct cmdline_saved_param_set saves[NPRIORITIES]; static void cmdline_save_param(const char *p, const char *value, int pri) { - if (saves[pri].nsaved >= saves[pri].savesize) { - saves[pri].savesize = saves[pri].nsaved + 32; - saves[pri].params = sresize(saves[pri].params, saves[pri].savesize, - struct cmdline_saved_param); - } + sgrowarray(saves[pri].params, saves[pri].savesize, saves[pri].nsaved); saves[pri].params[saves[pri].nsaved].p = dupstr(p); saves[pri].params[saves[pri].nsaved].value = dupstr(value); saves[pri].nsaved++; diff --git a/dialog.c b/dialog.c index d00e2529..c1e0a2b6 100644 --- a/dialog.c +++ b/dialog.c @@ -138,10 +138,7 @@ struct controlset *ctrl_settitle(struct controlbox *b, s->ncontrols = s->ctrlsize = 0; s->ncolumns = 0; /* this is a title! */ s->ctrls = NULL; - if (b->nctrlsets >= b->ctrlsetsize) { - b->ctrlsetsize = b->nctrlsets + 32; - b->ctrlsets = sresize(b->ctrlsets, b->ctrlsetsize,struct controlset *); - } + sgrowarray(b->ctrlsets, b->ctrlsetsize, b->nctrlsets); if (index < b->nctrlsets) memmove(&b->ctrlsets[index+1], &b->ctrlsets[index], (b->nctrlsets-index) * sizeof(*b->ctrlsets)); @@ -170,10 +167,7 @@ struct controlset *ctrl_getset(struct controlbox *b, const char *path, s->ncolumns = 1; s->ncontrols = s->ctrlsize = 0; s->ctrls = NULL; - if (b->nctrlsets >= b->ctrlsetsize) { - b->ctrlsetsize = b->nctrlsets + 32; - b->ctrlsets = sresize(b->ctrlsets, b->ctrlsetsize,struct controlset *); - } + sgrowarray(b->ctrlsets, b->ctrlsetsize, b->nctrlsets); if (index < b->nctrlsets) memmove(&b->ctrlsets[index+1], &b->ctrlsets[index], (b->nctrlsets-index) * sizeof(*b->ctrlsets)); @@ -192,11 +186,8 @@ void *ctrl_alloc_with_free(struct controlbox *b, size_t size, * use smalloc directly. */ p = smalloc(size); - if (b->nfrees >= b->freesize) { - b->freesize = b->nfrees + 32; - b->frees = sresize(b->frees, b->freesize, void *); - b->freefuncs = sresize(b->freefuncs, b->freesize, ctrl_freefn_t); - } + sgrowarray(b->frees, b->freesize, b->nfrees); + b->freefuncs = sresize(b->freefuncs, b->freesize, ctrl_freefn_t); b->frees[b->nfrees] = p; b->freefuncs[b->nfrees] = freefunc; b->nfrees++; @@ -218,10 +209,7 @@ static union control *ctrl_new(struct controlset *s, int type, intorptr context) { union control *c = snew(union control); - if (s->ncontrols >= s->ctrlsize) { - s->ctrlsize = s->ncontrols + 32; - s->ctrls = sresize(s->ctrls, s->ctrlsize, union control *); - } + sgrowarray(s->ctrls, s->ctrlsize, s->ncontrols); s->ctrls[s->ncontrols++] = c; /* * Fill in the standard fields. diff --git a/dialog.h b/dialog.h index 864471bb..6ccda341 100644 --- a/dialog.h +++ b/dialog.h @@ -422,8 +422,8 @@ struct controlset { char *boxname; /* internal short name of controlset */ char *boxtitle; /* title of container box */ int ncolumns; /* current no. of columns at bottom */ - int ncontrols; /* number of `union control' in array */ - int ctrlsize; /* allocated size of array */ + size_t ncontrols; /* number of `union control' in array */ + size_t ctrlsize; /* allocated size of array */ union control **ctrls; /* actual array */ }; @@ -434,11 +434,11 @@ typedef void (*ctrl_freefn_t)(void *); /* used by ctrl_alloc_with_free */ * controls. */ struct controlbox { - int nctrlsets; /* number of ctrlsets */ - int ctrlsetsize; /* ctrlset size */ + size_t nctrlsets; /* number of ctrlsets */ + size_t ctrlsetsize; /* ctrlset size */ struct controlset **ctrlsets; /* actual array of ctrlsets */ - int nfrees; - int freesize; + size_t nfrees; + size_t freesize; void **frees; /* array of aux data areas to free */ ctrl_freefn_t *freefuncs; /* parallel array of free functions */ }; diff --git a/ldisc.c b/ldisc.c index 0779d142..660e05d6 100644 --- a/ldisc.c +++ b/ldisc.c @@ -291,10 +291,7 @@ void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, bool interactive) /* FALLTHROUGH */ default: /* get to this label from ^V handler */ default_case: - if (ldisc->buflen >= ldisc->bufsiz) { - ldisc->bufsiz = ldisc->buflen + 256; - ldisc->buf = sresize(ldisc->buf, ldisc->bufsiz, char); - } + sgrowarray(ldisc->buf, ldisc->bufsiz, ldisc->buflen); ldisc->buf[ldisc->buflen++] = c; if (ECHOING) pwrite(ldisc, (unsigned char) c); diff --git a/ldisc.h b/ldisc.h index 65a544ad..770b4b05 100644 --- a/ldisc.h +++ b/ldisc.h @@ -20,7 +20,7 @@ struct Ldisc_tag { int protocol, localecho, localedit; char *buf; - int buflen, bufsiz; + size_t buflen, bufsiz; bool quotenext; }; diff --git a/memory.c b/memory.c index 1cb36ed0..448d9bd8 100644 --- a/memory.c +++ b/memory.c @@ -2,6 +2,7 @@ * PuTTY's memory allocation wrappers. */ +#include #include #include @@ -69,3 +70,45 @@ void safefree(void *ptr) #endif } } + +void *safegrowarray(void *ptr, size_t *allocated, size_t eltsize, + size_t oldlen, size_t extralen) +{ + /* The largest value we can safely multiply by eltsize */ + assert(eltsize > 0); + size_t maxsize = (~(size_t)0) / eltsize; + + size_t oldsize = *allocated; + + /* Range-check the input values */ + assert(oldsize <= maxsize); + assert(oldlen <= maxsize); + assert(extralen <= maxsize - oldlen); + + /* If the size is already enough, don't bother doing anything! */ + if (oldsize > oldlen + extralen) + return ptr; + + /* Find out how much we need to grow the array by. */ + size_t increment = (oldlen + extralen) - oldsize; + + /* Invent a new size. We want to grow the array by at least + * 'increment' elements; by at least a fixed number of bytes (to + * get things started when sizes are small); and by some constant + * factor of its old size (to avoid repeated calls to this + * function taking quadratic time overall). */ + if (increment < 256 / eltsize) + increment = 256 / eltsize; + if (increment < oldsize / 16) + increment = oldsize / 16; + + /* But we also can't grow beyond maxsize. */ + size_t maxincr = maxsize - oldsize; + if (increment > maxincr) + increment = maxincr; + + size_t newsize = oldsize + increment; + void *toret = saferealloc(ptr, newsize, eltsize); + *allocated = newsize; + return toret; +} diff --git a/misc.c b/misc.c index b7a188dd..fea296b6 100644 --- a/misc.c +++ b/misc.c @@ -39,7 +39,7 @@ prompts_t *new_prompts(void) { prompts_t *p = snew(prompts_t); p->prompts = NULL; - p->n_prompts = 0; + p->n_prompts = p->prompts_size = 0; p->data = NULL; p->to_server = true; /* to be on the safe side */ p->name = p->instruction = NULL; @@ -53,9 +53,8 @@ void add_prompt(prompts_t *p, char *promptstr, bool echo) pr->echo = echo; pr->result = NULL; pr->resultsize = 0; - p->n_prompts++; - p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *); - p->prompts[p->n_prompts-1] = pr; + sgrowarray(p->prompts, p->prompts_size, p->n_prompts); + p->prompts[p->n_prompts++] = pr; } void prompt_ensure_result_size(prompt_t *pr, int newlen) { diff --git a/misc.h b/misc.h index 8da4fdba..1adaf161 100644 --- a/misc.h +++ b/misc.h @@ -37,7 +37,7 @@ void burnstr(char *string); struct strbuf { char *s; unsigned char *u; - int len; + size_t len; BinarySink_IMPLEMENTATION; /* (also there's a surrounding implementation struct in misc.c) */ }; diff --git a/pscp.c b/pscp.c index c78d25f6..367cb28a 100644 --- a/pscp.c +++ b/pscp.c @@ -609,7 +609,7 @@ void scp_sftp_listdir(const char *dirname) struct fxp_name *ournames; struct sftp_packet *pktin; struct sftp_request *req; - int nnames, namesize; + size_t nnames, namesize; int i; if (!fxp_init()) { @@ -648,10 +648,7 @@ void scp_sftp_listdir(const char *dirname) break; } - if (nnames + names->nnames >= namesize) { - namesize += names->nnames + 128; - ournames = sresize(ournames, namesize, struct fxp_name); - } + sgrowarrayn(ournames, namesize, nnames, names->nnames); for (i = 0; i < names->nnames; i++) ournames[nnames++] = names->names[i]; @@ -1196,7 +1193,7 @@ int scp_get_sink_action(struct scp_sink_action *act) if (attrs.permissions & 0040000) { struct scp_sftp_dirstack *newitem; struct fxp_handle *dirhandle; - int nnames, namesize; + size_t nnames, namesize; struct fxp_name *ournames; struct fxp_names *names; @@ -1279,10 +1276,7 @@ int scp_get_sink_action(struct scp_sink_action *act) fxp_free_names(names); break; } - if (nnames + names->nnames >= namesize) { - namesize += names->nnames + 128; - ournames = sresize(ournames, namesize, struct fxp_name); - } + sgrowarrayn(ournames, namesize, nnames, names->nnames); for (i = 0; i < names->nnames; i++) { if (!strcmp(names->names[i].filename, ".") || !strcmp(names->names[i].filename, "..")) { diff --git a/psftp.c b/psftp.c index f896ac2f..7adbab70 100644 --- a/psftp.c +++ b/psftp.c @@ -264,7 +264,7 @@ bool sftp_get_file(char *fname, char *outfname, bool recurse, bool restart) (attrs.permissions & 0040000)) { struct fxp_handle *dirhandle; - int nnames, namesize; + size_t nnames, namesize; struct fxp_name **ournames; struct fxp_names *names; int i; @@ -321,10 +321,7 @@ bool sftp_get_file(char *fname, char *outfname, bool recurse, bool restart) fxp_free_names(names); break; } - if (nnames + names->nnames >= namesize) { - namesize += names->nnames + 128; - ournames = sresize(ournames, namesize, struct fxp_name *); - } + sgrowarrayn(ournames, namesize, nnames, names->nnames); for (i = 0; i < names->nnames; i++) if (strcmp(names->names[i].filename, ".") && strcmp(names->names[i].filename, "..")) { @@ -549,11 +546,11 @@ bool sftp_put_file(char *fname, char *outfname, bool recurse, bool restart) */ if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) { bool result; - int nnames, namesize; + size_t nnames, namesize; char *name, **ournames; const char *opendir_err; DirHandle *dh; - int i; + size_t i; /* * First, attempt to create the destination directory, @@ -588,10 +585,7 @@ bool sftp_put_file(char *fname, char *outfname, bool recurse, bool restart) return false; } while ((name = read_filename(dh)) != NULL) { - if (nnames >= namesize) { - namesize += 128; - ournames = sresize(ournames, namesize, char *); - } + sgrowarray(ournames, namesize, nnames); ournames[nnames++] = name; } close_directory(dh); @@ -647,7 +641,7 @@ bool sftp_put_file(char *fname, char *outfname, bool recurse, bool restart) sfree(nextoutfname); sfree(nextfname); if (!retd) { - for (i = 0; i < nnames; i++) { + for (size_t i = 0; i < nnames; i++) { sfree(ournames[i]); } sfree(ournames); @@ -658,7 +652,7 @@ bool sftp_put_file(char *fname, char *outfname, bool recurse, bool restart) /* * Done this recursion level. Free everything. */ - for (i = 0; i < nnames; i++) { + for (size_t i = 0; i < nnames; i++) { sfree(ournames[i]); } sfree(ournames); @@ -988,7 +982,7 @@ bool is_wildcard(char *name) */ struct sftp_command { char **words; - int nwords, wordssize; + size_t nwords, wordssize; int (*obey) (struct sftp_command *); /* returns <0 to quit */ }; @@ -1035,12 +1029,11 @@ int sftp_cmd_ls(struct sftp_command *cmd) struct fxp_handle *dirh; struct fxp_names *names; struct fxp_name **ournames; - int nnames, namesize; + size_t nnames, namesize; const char *dir; char *cdir, *unwcdir, *wildcard; struct sftp_packet *pktin; struct sftp_request *req; - int i; if (!backend) { not_connected(); @@ -1114,12 +1107,9 @@ int sftp_cmd_ls(struct sftp_command *cmd) break; } - if (nnames + names->nnames >= namesize) { - namesize += names->nnames + 128; - ournames = sresize(ournames, namesize, struct fxp_name *); - } + sgrowarrayn(ournames, namesize, nnames, names->nnames); - for (i = 0; i < names->nnames; i++) + for (size_t i = 0; i < names->nnames; i++) if (!wildcard || wc_match(wildcard, names->names[i].filename)) ournames[nnames++] = fxp_dup_name(&names->names[i]); @@ -1139,7 +1129,7 @@ int sftp_cmd_ls(struct sftp_command *cmd) /* * And print them. */ - for (i = 0; i < nnames; i++) { + for (size_t i = 0; i < nnames; i++) { with_stripctrl(san, ournames[i]->longname) printf("%s\n", san); fxp_free_name(ournames[i]); @@ -2257,8 +2247,8 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags) * exactly two words: one containing the !, and the second * containing everything else on the line. */ - cmd->nwords = cmd->wordssize = 2; - cmd->words = sresize(cmd->words, cmd->wordssize, char *); + cmd->nwords = 2; + sgrowarrayn(cmd->words, cmd->wordssize, cmd->nwords, 0); cmd->words[0] = dupstr("!"); cmd->words[1] = dupstr(p+1); } else if (*p == '#') { @@ -2307,10 +2297,7 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags) if (*p) p++; /* skip over the whitespace */ *r = '\0'; - if (cmd->nwords >= cmd->wordssize) { - cmd->wordssize = cmd->nwords + 16; - cmd->words = sresize(cmd->words, cmd->wordssize, char *); - } + sgrowarray(cmd->words, cmd->wordssize, cmd->nwords); cmd->words[cmd->nwords++] = dupstr(q); } } diff --git a/putty.h b/putty.h index cc14e6e7..e3767eec 100644 --- a/putty.h +++ b/putty.h @@ -665,6 +665,7 @@ typedef struct { bool instr_reqd; /* Display of `instruction' required or optional? */ size_t n_prompts; /* May be zero (in which case display the foregoing, * if any, and return success) */ + size_t prompts_size; /* allocated storage capacity for prompts[] */ prompt_t **prompts; void *data; /* slot for housekeeping data, managed by * seat_get_userpass_input(); initially NULL */ diff --git a/puttymem.h b/puttymem.h index e90d7c71..ddb04a5c 100644 --- a/puttymem.h +++ b/puttymem.h @@ -48,6 +48,47 @@ void safefree(void *); #define snew_plus(type, extra) ((type *)snmalloc(1, sizeof(type) + (extra))) #define snew_plus_get_aux(ptr) ((void *)((ptr) + 1)) +/* + * Helper macros to deal with the common use case of growing an array. + * + * The common setup is that 'array' is a pointer to the first element + * of a dynamic array of some type, and 'size' represents the current + * allocated size of that array (in elements). Both of those macro + * parameters are implicitly written back to. + * + * Then sgrowarray(array, size, n) means: make sure the nth element of + * the array exists (i.e. the size is at least n+1). You call that + * before writing to the nth element, if you're looping round + * appending to the array. + * + * If you need to grow the array by more than one element, you can + * instead call sgrowarrayn(array, size, n, m), which will ensure the + * size of the array is at least n+m. (So sgrowarray is just the + * special case of that in which m == 1.) + * + * It's common to call sgrowarrayn with one of n,m equal to the + * previous logical length of the array, and the other equal to the + * new number of logical entries you want to add, so that n <= size on + * entry. But that's not actually a mandatory precondition: the two + * length parameters are just arbitrary integers that get added + * together with an initial check for overflow, and the semantics are + * simply 'make sure the array is big enough to take their sum, no + * matter how big it was to start with'.) + * + * Another occasionally useful idiom is to call sgrowarray with n == + * size, i.e. sgrowarray(array, size, size). That just means: make + * array bigger by _some_ amount, I don't particularly mind how much. + * You might use that style if you were repeatedly calling an API + * function outside your control, which would either fill your buffer + * and return success, or else return a 'too big' error without + * telling you how much bigger it needed to be. + */ +void *safegrowarray(void *array, size_t *size, size_t eltsize, + size_t oldlen, size_t extralen); +#define sgrowarrayn(array, size, n, m) \ + ((array) = safegrowarray(array, &(size), sizeof(*array), n, m)) +#define sgrowarray(array, size, n) sgrowarrayn(array, size, n, 1) + /* * This function is called by the innermost safemalloc/saferealloc * functions when allocation fails. Usually it's provided by misc.c diff --git a/sftp.h b/sftp.h index 2b388b65..0b4ad92d 100644 --- a/sftp.h +++ b/sftp.h @@ -126,8 +126,7 @@ struct sftp_request; struct sftp_packet { char *data; - unsigned length, maxlen; - unsigned savedpos; + size_t length, maxlen, savedpos; int type; BinarySink_IMPLEMENTATION; BinarySource_IMPLEMENTATION; diff --git a/sftpcommon.c b/sftpcommon.c index aef6c247..34ba4247 100644 --- a/sftpcommon.c +++ b/sftpcommon.c @@ -15,18 +15,12 @@ static void sftp_pkt_BinarySink_write( BinarySink *bs, const void *data, size_t length) { struct sftp_packet *pkt = BinarySink_DOWNCAST(bs, struct sftp_packet); - unsigned newlen; assert(length <= 0xFFFFFFFFU - pkt->length); - newlen = pkt->length + length; - if (pkt->maxlen < newlen) { - pkt->maxlen = newlen * 5 / 4 + 256; - pkt->data = sresize(pkt->data, pkt->maxlen, char); - } - + sgrowarrayn(pkt->data, pkt->maxlen, pkt->length, length); memcpy(pkt->data + pkt->length, data, length); - pkt->length = newlen; + pkt->length += length; } struct sftp_packet *sftp_pkt_init(int type) diff --git a/ssh.c b/ssh.c index 73aa3557..dca0a728 100644 --- a/ssh.c +++ b/ssh.c @@ -981,7 +981,7 @@ static void ssh_size(Backend *be, int width, int height) struct ssh_add_special_ctx { SessionSpecial *specials; - int nspecials, specials_size; + size_t nspecials, specials_size; }; static void ssh_add_special(void *vctx, const char *text, @@ -990,12 +990,7 @@ static void ssh_add_special(void *vctx, const char *text, struct ssh_add_special_ctx *ctx = (struct ssh_add_special_ctx *)vctx; SessionSpecial *spec; - if (ctx->nspecials >= ctx->specials_size) { - ctx->specials_size = ctx->nspecials * 5 / 4 + 32; - ctx->specials = sresize(ctx->specials, ctx->specials_size, - SessionSpecial); - } - + sgrowarray(ctx->specials, ctx->specials_size, ctx->nspecials); spec = &ctx->specials[ctx->nspecials++]; spec->name = text; spec->code = code; diff --git a/ssh.h b/ssh.h index 3af4065b..e769e5f7 100644 --- a/ssh.h +++ b/ssh.h @@ -63,12 +63,12 @@ typedef struct PktIn { } PktIn; typedef struct PktOut { - long prefix; /* bytes up to and including type field */ - long length; /* total bytes, including prefix */ + size_t prefix; /* bytes up to and including type field */ + size_t length; /* total bytes, including prefix */ int type; - long minlen; /* SSH-2: ensure wire length is at least this */ + size_t minlen; /* SSH-2: ensure wire length is at least this */ unsigned char *data; /* allocated storage */ - long maxlen; /* amount of storage allocated for `data' */ + size_t maxlen; /* amount of storage allocated for `data' */ /* Extra metadata used in SSH packet logging mode, allowing us to * log in the packet header line that the packet came from a diff --git a/sshcommon.c b/sshcommon.c index 65cce855..e49eb0ee 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -230,18 +230,11 @@ PktOut *ssh_new_packet(void) return pkt; } -static void ssh_pkt_ensure(PktOut *pkt, int length) -{ - if (pkt->maxlen < length) { - pkt->maxlen = length + 256; - pkt->data = sresize(pkt->data, pkt->maxlen, unsigned char); - } -} static void ssh_pkt_adddata(PktOut *pkt, const void *data, int len) { + sgrowarrayn(pkt->data, pkt->maxlen, pkt->length, len); + memcpy(pkt->data + pkt->length, data, len); pkt->length += len; - ssh_pkt_ensure(pkt, pkt->length); - memcpy(pkt->data + pkt->length - len, data, len); } static void ssh_pkt_BinarySink_write(BinarySink *bs, diff --git a/terminal.c b/terminal.c index 929e1ec8..4f6776c8 100644 --- a/terminal.c +++ b/terminal.c @@ -4869,14 +4869,11 @@ static void term_bidi_cache_store(Terminal *term, int line, termchar *lbefore, termchar *lafter, bidi_char *wcTo, int width, int size) { - int i, j; + size_t i, j; if (!term->pre_bidi_cache || term->bidi_cache_size <= line) { - j = term->bidi_cache_size; - term->bidi_cache_size = line+1; - term->pre_bidi_cache = sresize(term->pre_bidi_cache, - term->bidi_cache_size, - struct bidi_cache_entry); + j = term->bidi_cache_size; + sgrowarray(term->pre_bidi_cache, term->bidi_cache_size, line); term->post_bidi_cache = sresize(term->post_bidi_cache, term->bidi_cache_size, struct bidi_cache_entry); @@ -5061,7 +5058,7 @@ static void do_paint(Terminal *term) int rv, cursor; pos scrpos; wchar_t *ch; - int chlen; + size_t chlen; termchar *newline; chlen = 1024; @@ -5375,10 +5372,7 @@ static void do_paint(Terminal *term) dirty_run = true; } - if (ccount+2 > chlen) { - chlen = ccount + 256; - ch = sresize(ch, chlen, wchar_t); - } + sgrowarrayn(ch, chlen, ccount, 2); #ifdef PLATFORM_IS_UTF16 if (tchar > 0x10000 && tchar < 0x110000) { @@ -5409,10 +5403,7 @@ static void do_paint(Terminal *term) break; } - if (ccount+2 > chlen) { - chlen = ccount + 256; - ch = sresize(ch, chlen, wchar_t); - } + sgrowarrayn(ch, chlen, ccount, 2); #ifdef PLATFORM_IS_UTF16 if (schar > 0x10000 && schar < 0x110000) { @@ -5552,8 +5543,8 @@ void term_scroll_to_selection(Terminal *term, int which_end) * Helper routine for clipme(): growing buffer. */ typedef struct { - int buflen; /* amount of allocated space in textbuf/attrbuf */ - int bufpos; /* amount of actual data */ + size_t bufsize; /* amount of allocated space in textbuf/attrbuf */ + size_t bufpos; /* amount of actual data */ wchar_t *textbuf; /* buffer for copied text */ wchar_t *textptr; /* = textbuf + bufpos (current insertion point) */ int *attrbuf; /* buffer for copied attributes */ @@ -5564,13 +5555,12 @@ typedef struct { static void clip_addchar(clip_workbuf *b, wchar_t chr, int attr, truecolour tc) { - if (b->bufpos >= b->buflen) { - b->buflen *= 2; - b->textbuf = sresize(b->textbuf, b->buflen, wchar_t); + if (b->bufpos >= b->bufsize) { + sgrowarray(b->textbuf, b->bufsize, b->bufpos); b->textptr = b->textbuf + b->bufpos; - b->attrbuf = sresize(b->attrbuf, b->buflen, int); + b->attrbuf = sresize(b->attrbuf, b->bufsize, int); b->attrptr = b->attrbuf + b->bufpos; - b->tcbuf = sresize(b->tcbuf, b->buflen, truecolour); + b->tcbuf = sresize(b->tcbuf, b->bufsize, truecolour); b->tcptr = b->tcbuf + b->bufpos; } *b->textptr++ = chr; @@ -5587,11 +5577,11 @@ static void clipme(Terminal *term, pos top, pos bottom, bool rect, bool desel, int attr; truecolour tc; - buf.buflen = 5120; + buf.bufsize = 5120; buf.bufpos = 0; - buf.textptr = buf.textbuf = snewn(buf.buflen, wchar_t); - buf.attrptr = buf.attrbuf = snewn(buf.buflen, int); - buf.tcptr = buf.tcbuf = snewn(buf.buflen, truecolour); + buf.textptr = buf.textbuf = snewn(buf.bufsize, wchar_t); + buf.attrptr = buf.attrbuf = snewn(buf.bufsize, int); + buf.tcptr = buf.tcbuf = snewn(buf.bufsize, truecolour); old_top_x = top.x; /* needed for rect==1 */ diff --git a/terminal.h b/terminal.h index b130f886..7981fd33 100644 --- a/terminal.h +++ b/terminal.h @@ -270,7 +270,7 @@ struct terminal_tag { bidi_char *wcFrom, *wcTo; int wcFromTo_size; struct bidi_cache_entry *pre_bidi_cache, *post_bidi_cache; - int bidi_cache_size; + size_t bidi_cache_size; /* * We copy a bunch of stuff out of the Conf structure into local diff --git a/testcrypt.c b/testcrypt.c index 0421747b..8071c013 100644 --- a/testcrypt.c +++ b/testcrypt.c @@ -380,10 +380,7 @@ size_t nfinalisers, finalisersize; static void add_finaliser(finaliser_fn_t fn, void *ctx) { - if (nfinalisers >= finalisersize) { - finalisersize = nfinalisers * 5 / 4 + 16; - finalisers = sresize(finalisers, finalisersize, struct finaliser); - } + sgrowarray(finalisers, finalisersize, nfinalisers); finalisers[nfinalisers].fn = fn; finalisers[nfinalisers].ctx = ctx; nfinalisers++; diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 1d00a22e..b8ed07cf 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -93,7 +93,7 @@ struct dlgparam { GtkWidget *currtreeitem, **treeitems; int ntreeitems; #else - int nselparams; + size_t nselparams; struct selparam *selparams; #endif struct controlbox *ctrlbox; @@ -2918,7 +2918,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, struct Shortcuts scs; struct selparam *selparams = NULL; - int nselparams = 0, selparamsize = 0; + size_t nselparams = 0, selparamsize = 0; dp = snew(struct dlgparam); dp->after = after; @@ -3040,11 +3040,7 @@ GtkWidget *create_config_box(const char *title, Conf *conf, page_num); } - if (nselparams >= selparamsize) { - selparamsize += 16; - selparams = sresize(selparams, selparamsize, - struct selparam); - } + sgrowarray(selparams, selparamsize, nselparams); selparams[nselparams].dp = dp; selparams[nselparams].panels = GTK_NOTEBOOK(panels); selparams[nselparams].panel = panelvbox; @@ -3243,8 +3239,7 @@ static void dlgparam_destroy(GtkWidget *widget, gpointer data) ctrl_free_box(dp->ctrlbox); #if GTK_CHECK_VERSION(2,0,0) if (dp->selparams) { - int i; - for (i = 0; i < dp->nselparams; i++) + for (size_t i = 0; i < dp->nselparams; i++) if (dp->selparams[i].treepath) gtk_tree_path_free(dp->selparams[i].treepath); sfree(dp->selparams); diff --git a/unix/gtkmain.c b/unix/gtkmain.c index 20826726..9cd32c26 100644 --- a/unix/gtkmain.c +++ b/unix/gtkmain.c @@ -170,7 +170,7 @@ void launch_duplicate_session(Conf *conf) for (i = 0; pty_argv[i]; i++) put_asciz(serialised, pty_argv[i]); - sprintf(option, "---[%d,%d]", pipefd[0], serialised->len); + sprintf(option, "---[%d,%zu]", pipefd[0], serialised->len); noncloexec(pipefd[0]); fork_and_exec_self(pipefd[1], option, NULL); close(pipefd[0]); diff --git a/unix/uxnet.c b/unix/uxnet.c index 0074c4b8..b60b933a 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -1584,18 +1584,16 @@ int net_service_lookup(char *service) char *get_hostname(void) { - int len = 128; + size_t size = 0; char *hostname = NULL; do { - len *= 2; - hostname = sresize(hostname, len, char); - if ((gethostname(hostname, len) < 0) && - (errno != ENAMETOOLONG)) { + sgrowarray(hostname, size, size); + if ((gethostname(hostname, size) < 0) && (errno != ENAMETOOLONG)) { sfree(hostname); hostname = NULL; break; } - } while (strlen(hostname) >= len-1); + } while (strlen(hostname) >= size-1); return hostname; } diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 706345d1..d7fc90d0 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -734,7 +734,8 @@ void run_agent(void) unsigned long now; int *fdlist; int fd; - int i, fdsize, fdstate; + int i, fdstate; + size_t fdsize; int termination_pid = -1; bool errors = false; Conf *conf; @@ -882,10 +883,7 @@ void run_agent(void) fd = next_fd(&fdstate, &rwx)) i++; /* Expand the fdlist buffer if necessary. */ - if (i > fdsize) { - fdsize = i + 16; - fdlist = sresize(fdlist, fdsize, int); - } + sgrowarray(fdlist, fdsize, i); /* * Add all currently open fds to the select sets, and store diff --git a/unix/uxplink.c b/unix/uxplink.c index 5aae9e49..f7fc1126 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -568,7 +568,8 @@ int main(int argc, char **argv) bool sending; int *fdlist; int fd; - int i, fdsize, fdstate; + int i, fdstate; + size_t fdsize; int exitcode; bool errors; enum TriState sanitise_stdout = AUTO, sanitise_stderr = AUTO; @@ -909,10 +910,7 @@ int main(int argc, char **argv) fd = next_fd(&fdstate, &rwx)) i++; /* Expand the fdlist buffer if necessary. */ - if (i > fdsize) { - fdsize = i + 16; - fdlist = sresize(fdlist, fdsize, int); - } + sgrowarray(fdlist, fdsize, i); /* * Add all currently open fds to the select sets, and store diff --git a/unix/uxserver.c b/unix/uxserver.c index 12a9e6a5..1771c272 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -360,11 +360,12 @@ int main(int argc, char **argv) { int *fdlist; int fd; - int i, fdsize, fdstate; + int i, fdstate; + size_t fdsize; unsigned long now; ssh_key **hostkeys = NULL; - int nhostkeys = 0, hostkeysize = 0; + size_t nhostkeys = 0, hostkeysize = 0; RSAKey *hostkey1 = NULL; AuthPolicy ap; @@ -434,10 +435,7 @@ int main(int argc, char **argv) exit(1); } - if (nhostkeys >= hostkeysize) { - hostkeysize = nhostkeys * 5 / 4 + 16; - hostkeys = sresize(hostkeys, hostkeysize, ssh_key *); - } + sgrowarray(hostkeys, hostkeysize, nhostkeys); hostkeys[nhostkeys++] = key; } else if (keytype == SSH_KEYTYPE_SSH1) { if (hostkey1) { @@ -578,10 +576,7 @@ int main(int argc, char **argv) fd = next_fd(&fdstate, &rwx)) i++; /* Expand the fdlist buffer if necessary. */ - if (i > fdsize) { - fdsize = i + 16; - fdlist = sresize(fdlist, fdsize, int); - } + sgrowarray(fdlist, fdsize, i); /* * Add all currently open fds to the select sets, and store diff --git a/unix/uxsftp.c b/unix/uxsftp.c index 81691e70..0afd2a13 100644 --- a/unix/uxsftp.c +++ b/unix/uxsftp.c @@ -98,7 +98,7 @@ char *psftp_lcd(char *dir) char *psftp_getcwd(void) { char *buffer, *ret; - int size = 256; + size_t size = 256; buffer = snewn(size, char); while (1) { @@ -113,8 +113,7 @@ char *psftp_getcwd(void) * Otherwise, ERANGE was returned, meaning the buffer * wasn't big enough. */ - size = size * 3 / 2; - buffer = sresize(buffer, size, char); + sgrowarray(buffer, size, size); } } @@ -447,7 +446,8 @@ char *dir_file_cat(const char *dir, const char *file) static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok) { fd_set rset, wset, xset; - int i, fdsize, *fdlist; + int i, *fdlist; + size_t fdsize; int fd, fdcount, fdstate, rwx, ret, maxfd; unsigned long now = GETTICKCOUNT(); unsigned long next; @@ -467,10 +467,7 @@ static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok) return -1; /* doom */ /* Expand the fdlist buffer if necessary. */ - if (i > fdsize) { - fdsize = i + 16; - fdlist = sresize(fdlist, fdsize, int); - } + sgrowarray(fdlist, fdsize, i); FD_ZERO(&rset); FD_ZERO(&wset); @@ -571,7 +568,8 @@ int ssh_sftp_loop_iteration(void) char *ssh_sftp_get_cmdline(const char *prompt, bool no_fds_ok) { char *buf; - int buflen, bufsize, ret; + size_t buflen, bufsize; + int ret; fputs(prompt, stdout); fflush(stdout); @@ -587,10 +585,7 @@ char *ssh_sftp_get_cmdline(const char *prompt, bool no_fds_ok) return NULL; /* woop woop */ } if (ret > 0) { - if (buflen >= bufsize) { - bufsize = buflen + 512; - buf = sresize(buf, bufsize, char); - } + sgrowarray(buf, bufsize, buflen); ret = read(0, buf+buflen, 1); if (ret < 0) { perror("read"); diff --git a/unix/uxsftpserver.c b/unix/uxsftpserver.c index 534f6965..6fab0ba0 100644 --- a/unix/uxsftpserver.c +++ b/unix/uxsftpserver.c @@ -28,7 +28,7 @@ typedef struct UnixSftpServer UnixSftpServer; struct UnixSftpServer { unsigned *fdseqs; bool *fdsopen; - int fdsize; + size_t fdsize; tree234 *dirhandles; int last_dirhandle_index; @@ -74,9 +74,8 @@ static void uss_free(SftpServer *srv) { UnixSftpServer *uss = container_of(srv, UnixSftpServer, srv); struct uss_dirhandle *udh; - int i; - for (i = 0; i < uss->fdsize; i++) + for (size_t i = 0; i < uss->fdsize; i++) if (uss->fdsopen[i]) close(i); sfree(uss->fdseqs); @@ -118,9 +117,8 @@ static void uss_return_new_handle( { assert(fd >= 0); if (fd >= uss->fdsize) { - int old_size = uss->fdsize; - uss->fdsize = fd * 5 / 4 + 32; - uss->fdseqs = sresize(uss->fdseqs, uss->fdsize, unsigned); + size_t old_size = uss->fdsize; + sgrowarray(uss->fdseqs, uss->fdsize, fd); uss->fdsopen = sresize(uss->fdsopen, uss->fdsize, bool); while (old_size < uss->fdsize) { uss->fdseqs[old_size] = 0; diff --git a/unix/x11misc.c b/unix/x11misc.c index b49aa489..813773c2 100644 --- a/unix/x11misc.c +++ b/unix/x11misc.c @@ -34,12 +34,11 @@ struct x11_err_to_ignore { struct x11_err_to_ignore *errs; -int nerrs, errsize; +size_t nerrs, errsize; static int x11_error_handler(Display *thisdisp, XErrorEvent *err) { - int i; - for (i = 0; i < nerrs; i++) { + for (size_t i = 0; i < nerrs; i++) { if (thisdisp == errs[i].display && err->serial == errs[i].serial && err->error_code == errs[i].error_code) { @@ -65,7 +64,7 @@ void x11_ignore_error(Display *disp, unsigned char errcode) */ { unsigned long last = LastKnownRequestProcessed(disp); - int i, j; + size_t i, j; for (i = j = 0; i < nerrs; i++) { if (errs[i].display == disp && errs[i].serial <= last) continue; @@ -74,10 +73,7 @@ void x11_ignore_error(Display *disp, unsigned char errcode) nerrs = j; } - if (nerrs >= errsize) { - errsize = nerrs * 5 / 4 + 16; - errs = sresize(errs, errsize, struct x11_err_to_ignore); - } + sgrowarray(errs, errsize, nerrs); errs[nerrs].display = disp; errs[nerrs].error_code = errcode; errs[nerrs].serial = NextRequest(disp); diff --git a/utils.c b/utils.c index 3f02bd66..ab0298e9 100644 --- a/utils.c +++ b/utils.c @@ -290,6 +290,18 @@ int string_length_for_printf(size_t s) return s; } +/* Work around lack of va_copy in old MSC */ +#if defined _MSC_VER && !defined va_copy +#define va_copy(a, b) TYPECHECK( \ + (va_list *)0 == &(a) && (va_list *)0 == &(b), \ + memcpy(&a, &b, sizeof(va_list))) +#endif + +/* Also lack of vsnprintf before VS2015 */ +#if defined _WINDOWS && !defined __WINE__ && _MSC_VER < 1900 +#define vsnprintf _vsnprintf +#endif + /* * Do an sprintf(), but into a custom-allocated buffer. * @@ -325,65 +337,40 @@ int string_length_for_printf(size_t s) * directive we don't know about, we should panic and die rather * than run any risk. */ -static char *dupvprintf_inner(char *buf, int oldlen, int *oldsize, +static char *dupvprintf_inner(char *buf, size_t oldlen, size_t *sizeptr, const char *fmt, va_list ap) { - int len, size, newsize; + size_t len, size; - assert(*oldsize >= oldlen); - size = *oldsize - oldlen; - if (size == 0) { - size = 512; - newsize = oldlen + size; - buf = sresize(buf, newsize, char); - } else { - newsize = *oldsize; - } + size = *sizeptr; + sgrowarrayn(buf, size, oldlen, 512); while (1) { -#if defined _WINDOWS && !defined __WINE__ && _MSC_VER < 1900 /* 1900 == VS2015 has real snprintf */ -#define vsnprintf _vsnprintf -#endif -#ifdef va_copy - /* Use the `va_copy' macro mandated by C99, if present. - * XXX some environments may have this as __va_copy() */ va_list aq; va_copy(aq, ap); - len = vsnprintf(buf + oldlen, size, fmt, aq); + len = vsnprintf(buf + oldlen, size - oldlen, fmt, aq); va_end(aq); -#else - /* Ugh. No va_copy macro, so do something nasty. - * Technically, you can't reuse a va_list like this: it is left - * unspecified whether advancing a va_list pointer modifies its - * value or something it points to, so on some platforms calling - * vsnprintf twice on the same va_list might fail hideously - * (indeed, it has been observed to). - * XXX the autoconf manual suggests that using memcpy() will give - * "maximum portability". */ - len = vsnprintf(buf + oldlen, size, fmt, ap); -#endif + if (len >= 0 && len < size) { /* This is the C99-specified criterion for snprintf to have * been completely successful. */ - *oldsize = newsize; + *sizeptr = size; return buf; } else if (len > 0) { /* This is the C99 error condition: the returned length is * the required buffer size not counting the NUL. */ - size = len + 1; + sgrowarrayn(buf, size, oldlen, len + 1); } else { /* This is the pre-C99 glibc error condition: <0 means the * buffer wasn't big enough, so we enlarge it a bit and hope. */ - size += 512; + sgrowarray(buf, size, size); } - newsize = oldlen + size; - buf = sresize(buf, newsize, char); } } char *dupvprintf(const char *fmt, va_list ap) { - int size = 0; + size_t size = 0; return dupvprintf_inner(NULL, 0, &size, fmt, ap); } char *dupprintf(const char *fmt, ...) @@ -397,22 +384,21 @@ char *dupprintf(const char *fmt, ...) } struct strbuf_impl { - int size; + size_t size; struct strbuf visible; }; +#define STRBUF_SET_UPTR(buf) \ + ((buf)->visible.u = (unsigned char *)(buf)->visible.s) #define STRBUF_SET_PTR(buf, ptr) \ - ((buf)->visible.s = (ptr), \ - (buf)->visible.u = (unsigned char *)(buf)->visible.s) + ((buf)->visible.s = (ptr), STRBUF_SET_UPTR(buf)) void *strbuf_append(strbuf *buf_o, size_t len) { struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible); char *toret; - if (buf->size < buf->visible.len + len + 1) { - buf->size = (buf->visible.len + len + 1) * 5 / 4 + 512; - STRBUF_SET_PTR(buf, sresize(buf->visible.s, buf->size, char)); - } + sgrowarrayn(buf->visible.s, buf->size, buf->visible.len + 1, len); + STRBUF_SET_UPTR(buf); toret = buf->visible.s + buf->visible.len; buf->visible.len += len; buf->visible.s[buf->visible.len] = '\0'; @@ -487,13 +473,12 @@ void strbuf_finalise_agent_query(strbuf *buf_o) char *fgetline(FILE *fp) { char *ret = snewn(512, char); - int size = 512, len = 0; + size_t size = 512, len = 0; while (fgets(ret + len, size - len, fp)) { len += strlen(ret + len); if (len > 0 && ret[len-1] == '\n') break; /* got a newline, we're done */ - size = len + 512; - ret = sresize(ret, size, char); + sgrowarrayn(ret, size, len, 512); } if (len == 0) { /* first fgets returned NULL */ sfree(ret); diff --git a/windows/window.c b/windows/window.c index 781e8b88..6c1e1931 100644 --- a/windows/window.c +++ b/windows/window.c @@ -3488,7 +3488,7 @@ static void do_text_internal( bool opaque; bool is_cursor = false; static int *lpDx = NULL; - static int lpDx_len = 0; + static size_t lpDx_len = 0; int *lpDx_maybe; int len2; /* for SURROGATE PAIR */ @@ -3699,9 +3699,7 @@ static void do_text_internal( } if (len > lpDx_len) { - lpDx_len = len * 9 / 8 + 16; - lpDx = sresize(lpDx, lpDx_len, int); - + sgrowarray(lpDx, lpDx_len, len); if (lpDx_maybe) lpDx_maybe = lpDx; } @@ -3780,14 +3778,10 @@ static void do_text_internal( lpDx[0] = -1; } else if (DIRECT_FONT(text[0])) { static char *directbuf = NULL; - static int directlen = 0; - int i; - if (len > directlen) { - directlen = len; - directbuf = sresize(directbuf, directlen, char); - } + static size_t directlen = 0; - for (i = 0; i < len; i++) + sgrowarray(directbuf, directlen, len); + for (size_t i = 0; i < len; i++) directbuf[i] = text[i] & 0xFF; ExtTextOut(wintw_hdc, x + xoffset, diff --git a/windows/winhandl.c b/windows/winhandl.c index 739e2666..6e2c4be0 100644 --- a/windows/winhandl.c +++ b/windows/winhandl.c @@ -541,7 +541,8 @@ HANDLE *handle_get_events(int *nevents) { HANDLE *ret; struct handle *h; - int i, n, size; + int i; + size_t n, size; /* * Go through our tree counting the handle objects currently @@ -552,10 +553,7 @@ HANDLE *handle_get_events(int *nevents) if (handles_by_evtomain) { for (i = 0; (h = index234(handles_by_evtomain, i)) != NULL; i++) { if (h->u.g.busy) { - if (n >= size) { - size += 32; - ret = sresize(ret, size, HANDLE); - } + sgrowarray(ret, size, n); ret[n++] = h->u.g.ev_to_main; } } diff --git a/windows/winmisc.c b/windows/winmisc.c index abba8085..2df3a6b0 100644 --- a/windows/winmisc.c +++ b/windows/winmisc.c @@ -223,16 +223,14 @@ HMODULE load_system32_dll(const char *libname) * path.) */ static char *sysdir = NULL; + static size_t sysdirsize = 0; char *fullpath; HMODULE ret; if (!sysdir) { - int size = 0, len; - do { - size = 3*size/2 + 512; - sysdir = sresize(sysdir, size, char); - len = GetSystemDirectory(sysdir, size); - } while (len >= size); + size_t len; + while ((len = GetSystemDirectory(sysdir, sysdirsize)) >= sysdirsize) + sgrowarray(sysdir, sysdirsize, len); } fullpath = dupcat(sysdir, "\\", libname, NULL); diff --git a/windows/winplink.c b/windows/winplink.c index 0bcb6564..37fb4890 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -262,7 +262,7 @@ int main(int argc, char **argv) { bool sending; SOCKET *sklist; - int skcount, sksize; + size_t skcount, sksize; int exitcode; bool errors; bool use_subsystem = false; @@ -579,10 +579,7 @@ int main(int argc, char **argv) socket = next_socket(&socketstate)) i++; /* Expand the buffer if necessary. */ - if (i > sksize) { - sksize = i + 16; - sklist = sresize(sklist, sksize, SOCKET); - } + sgrowarray(sklist, sksize, i); /* Retrieve the sockets into sklist. */ skcount = 0; diff --git a/windows/winsftp.c b/windows/winsftp.c index 31683e5a..45d38d57 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -63,7 +63,7 @@ char *psftp_lcd(char *dir) char *psftp_getcwd(void) { char *ret = snewn(256, char); - int len = GetCurrentDirectory(256, ret); + size_t len = GetCurrentDirectory(256, ret); if (len > 256) ret = sresize(ret, len, char); GetCurrentDirectory(len, ret); diff --git a/windows/winstore.c b/windows/winstore.c index 5f003354..c846bd66 100644 --- a/windows/winstore.c +++ b/windows/winstore.c @@ -298,8 +298,7 @@ bool enum_settings_next(settings_e *e, strbuf *sb) success = (retd == ERROR_SUCCESS); break; } - regbuf_size = regbuf_size * 5 / 4 + 256; - regbuf = sresize(regbuf, regbuf_size, char); + sgrowarray(regbuf, regbuf_size, regbuf_size); } if (success) diff --git a/windows/winutils.c b/windows/winutils.c index 5edde65b..a5fedb8e 100644 --- a/windows/winutils.c +++ b/windows/winutils.c @@ -160,11 +160,10 @@ void pgp_fingerprints(void) char *GetDlgItemText_alloc(HWND hwnd, int id) { char *ret = NULL; - int size = 0; + size_t size = 0; do { - size = size * 4 / 3 + 512; - ret = sresize(ret, size, char); + sgrowarray(ret, size, size); GetDlgItemText(hwnd, id, ret, size); } while (!memchr(ret, '\0', size-1));