Blob
- Date:
- Message:
- rc: avoid undefined C There are two bugs in pdec() on INT_MIN: * wrong output. `n = 1-n' should be `n = -1-n' when n is INT_MIN. * infinite loop. gcc optimizes `if(n>=0)' into `if(true)' because `-INT_MIN' (signed integer overflow) is undefined behavior in C, and gcc assumes the negation of a negative number must be positive. The resulting binary keeps printing '-' forever given INT_MIN. Try the simplified pdec.c below. $ gcc pdec.c $ ./a.out -2147483648 --214748364* $ gcc pdec.c -O2 $ ./a.out -2147483648 <infinite loop> $ gcc pdec.c -O2 -D__PATCH__ $ ./a.out -2147483648 -2147483648 === pdec.c === #include <stdio.h> #include <stdlib.h> #include <limits.h> #define io void void pchr(io *f, int c) { putchar(c); } void pdec(io *f, int n) { if(n<0){ #ifndef __PATCH__ n=-n; if(n>=0){ pchr(f, '-'); pdec(f, n); return; } /* n is two's complement minimum integer */ n = 1-n; #else if(n!=INT_MIN){ pchr(f, '-'); pdec(f, -n); return; } /* n is two's complement minimum integer */ n = -(INT_MIN+1); #endif pchr(f, '-'); pdec(f, n/10); pchr(f, n%10+'1'); return; } if(n>9) pdec(f, n/10); pchr(f, n%10+'0'); } int main(int argc, char **argv) { int n = atoi(argv[1]); pdec(NULL, n); putchar('\n'); } R=rsc CC=plan9port.codebot https://codereview.appspot.com/7241055
- Actions:
- History | Blame | Raw File
1 #include <limits.h>2 #include "rc.h"3 #include "exec.h"4 #include "io.h"5 #include "fns.h"6 int pfmtnest = 0;8 void9 pfmt(io *f, char *fmt, ...)10 {11 va_list ap;12 char err[ERRMAX];13 va_start(ap, fmt);14 pfmtnest++;15 for(;*fmt;fmt++)16 if(*fmt!='%')17 pchr(f, *fmt);18 else switch(*++fmt){19 case '\0':20 va_end(ap);21 return;22 case 'c':23 pchr(f, va_arg(ap, int));24 break;25 case 'd':26 pdec(f, va_arg(ap, int));27 break;28 case 'o':29 poct(f, va_arg(ap, unsigned));30 break;31 case 'p':32 pptr(f, va_arg(ap, void*));33 break;34 case 'Q':35 pquo(f, va_arg(ap, char *));36 break;37 case 'q':38 pwrd(f, va_arg(ap, char *));39 break;40 case 'r':41 rerrstr(err, sizeof err); pstr(f, err);42 break;43 case 's':44 pstr(f, va_arg(ap, char *));45 break;46 case 't':47 pcmd(f, va_arg(ap, struct tree *));48 break;49 case 'v':50 pval(f, va_arg(ap, struct word *));51 break;52 default:53 pchr(f, *fmt);54 break;55 }56 va_end(ap);57 if(--pfmtnest==0)58 flush(f);59 }61 void62 pchr(io *b, int c)63 {64 if(b->bufp==b->ebuf)65 fullbuf(b, c);66 else *b->bufp++=c;67 }69 int70 rchr(io *b)71 {72 if(b->bufp==b->ebuf)73 return emptybuf(b);74 return *b->bufp++ & 0xFF;75 }77 void78 pquo(io *f, char *s)79 {80 pchr(f, '\'');81 for(;*s;s++)82 if(*s=='\'')83 pfmt(f, "''");84 else pchr(f, *s);85 pchr(f, '\'');86 }88 void89 pwrd(io *f, char *s)90 {91 char *t;92 for(t = s;*t;t++) if(!wordchr(*t)) break;93 if(t==s || *t)94 pquo(f, s);95 else pstr(f, s);96 }98 void99 pptr(io *f, void *v)100 {101 int n;102 uintptr p;104 p = (uintptr)v;105 if(sizeof(uintptr) == sizeof(uvlong) && p>>32)106 for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);108 for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);109 }111 void112 pstr(io *f, char *s)113 {114 if(s==0)115 s="(null)";116 while(*s) pchr(f, *s++);117 }119 void120 pdec(io *f, int n)121 {122 if(n<0){123 if(n!=INT_MIN){124 pchr(f, '-');125 pdec(f, -n);126 return;127 }128 /* n is two's complement minimum integer */129 n = -(INT_MIN+1);130 pchr(f, '-');131 pdec(f, n/10);132 pchr(f, n%10+'1');133 return;134 }135 if(n>9)136 pdec(f, n/10);137 pchr(f, n%10+'0');138 }140 void141 poct(io *f, unsigned n)142 {143 if(n>7)144 poct(f, n>>3);145 pchr(f, (n&7)+'0');146 }148 void149 pval(io *f, word *a)150 {151 if(a){152 while(a->next && a->next->word){153 pwrd(f, a->word);154 pchr(f, ' ');155 a = a->next;156 }157 pwrd(f, a->word);158 }159 }161 int162 fullbuf(io *f, int c)163 {164 flush(f);165 return *f->bufp++=c;166 }168 void169 flush(io *f)170 {171 int n;172 char *s;173 if(f->strp){174 n = f->ebuf-f->strp;175 f->strp = realloc(f->strp, n+101);176 if(f->strp==0)177 panic("Can't realloc %d bytes in flush!", n+101);178 f->bufp = f->strp+n;179 f->ebuf = f->bufp+100;180 for(s = f->bufp;s<=f->ebuf;s++) *s='\0';181 }182 else{183 n = f->bufp-f->buf;184 if(n && Write(f->fd, f->buf, n) < 0){185 Write(3, "Write error\n", 12);186 if(ntrap)187 dotrap();188 }189 f->bufp = f->buf;190 f->ebuf = f->buf+NBUF;191 }192 }194 io*195 openfd(int fd)196 {197 io *f = new(struct io);198 f->fd = fd;199 f->bufp = f->ebuf = f->buf;200 f->strp = 0;201 return f;202 }204 io*205 openstr(void)206 {207 io *f = new(struct io);208 char *s;209 f->fd=-1;210 f->bufp = f->strp = emalloc(101);211 f->ebuf = f->bufp+100;212 for(s = f->bufp;s<=f->ebuf;s++) *s='\0';213 return f;214 }215 /*216 * Open a corebuffer to read. EOF occurs after reading len217 * characters from buf.218 */220 io*221 opencore(char *s, int len)222 {223 io *f = new(struct io);224 char *buf = emalloc(len);225 f->fd= -1 /*open("/dev/null", 0)*/;226 f->bufp = f->strp = buf;227 f->ebuf = buf+len;228 Memcpy(buf, s, len);229 return f;230 }232 void233 iorewind(io *io)234 {235 if(io->fd==-1)236 io->bufp = io->strp;237 else{238 io->bufp = io->ebuf = io->buf;239 Seek(io->fd, 0L, 0);240 }241 }243 void244 closeio(io *io)245 {246 if(io->fd>=0)247 close(io->fd);248 if(io->strp)249 efree(io->strp);250 efree((char *)io);251 }253 int254 emptybuf(io *f)255 {256 int n;257 if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;258 f->bufp = f->buf;259 f->ebuf = f->buf+n;260 return *f->bufp++&0xff;261 }