Buffer overflow hunt: removing strcpy, strcat, sprintf
[fw/sdcc] / src / SDCC.lex
1 /*-----------------------------------------------------------------------
2   SDCC.lex - lexical analyser for use with sdcc ( a freeware compiler for
3   8/16 bit microcontrollers)
4   Written by : Sandeep Dutta . sandeep.dutta@usa.net (1997)
5   
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19     
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!  
23 -------------------------------------------------------------------------*/
24
25 D        [0-9]
26 L        [a-zA-Z_]
27 H        [a-fA-F0-9]
28 E        [Ee][+-]?{D}+
29 FS       (f|F|l|L)
30 IS       (u|U|l|L)*
31 %{
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include "common.h"
37 #include "newalloc.h"
38     
39 char *stringLiteral();
40 char *currFname;
41
42 extern int lineno, column;
43 extern char *filename ;
44 int   yylineno = 1               ;
45 void count()                     ;
46 int process_pragma(char *);
47 #undef yywrap
48
49 int yywrap YY_PROTO((void))
50 {
51    return(1);
52 }
53 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
54                                 check_type(yytext))
55 char *asmbuff=NULL;
56 int asmbuffSize=0;
57 char *asmp ;
58 extern int check_type           ();
59  extern int isTargetKeyword     ();
60 extern int checkCurrFile        (char *);
61 extern int processPragma        (char *);
62 extern int printListing         (int   );
63 struct optimize save_optimize ;
64 struct options  save_options  ;
65
66  enum {
67      P_SAVE = 1,
68      P_RESTORE ,
69      P_NOINDUCTION,
70      P_NOINVARIANT,
71      P_INDUCTION ,
72      P_STACKAUTO ,
73      P_NOJTBOUND ,
74      P_NOOVERLAY ,
75      P_NOGCSE    ,
76      P_CALLEE_SAVES,
77      P_EXCLUDE   ,
78      P_NOIV      ,
79      P_LOOPREV   ,
80      P_OVERLAY_      /* I had a strange conflict with P_OVERLAY while */
81                      /* cross-compiling for MINGW32 with gcc 3.2 */
82  };
83
84 %}
85 %x asm
86 %%
87 "_asm"         {  
88   count(); 
89   asmp = asmbuff = realloc (asmbuff, INITIAL_INLINEASM);
90   asmbuffSize=INITIAL_INLINEASM;
91   BEGIN(asm) ;
92 }
93 <asm>"_endasm" { 
94   count();
95   *asmp = '\0';
96   yylval.yyinline = strdup (asmbuff);
97   BEGIN(INITIAL);
98   return (INLINEASM);
99 }
100 <asm>.         { 
101   if (asmp-asmbuff >= asmbuffSize-2) {
102     // increase the buffersize with 50%
103     int size=asmp-asmbuff;
104     asmbuffSize=asmbuffSize*3/2;
105     asmbuff = realloc (asmbuff, asmbuffSize); 
106     asmp=asmbuff+size;
107   }
108   *asmp++ = yytext[0];
109 }
110 <asm>\n        { 
111   count(); 
112   if (asmp-asmbuff >= asmbuffSize-3) {
113     // increase the buffersize with 50%
114     int size=asmp-asmbuff;
115     asmbuffSize=asmbuffSize*3/2;
116     asmbuff = realloc (asmbuff, asmbuffSize); 
117     asmp=asmbuff+size;
118   }
119   *asmp++ = '\n' ;
120 }
121 "at"           { count(); TKEYWORD(AT)  ; }
122 "auto"         { count(); return(AUTO); }
123 "bit"          { count(); TKEYWORD(BIT) ; }
124 "break"        { count(); return(BREAK); }
125 "case"         { count(); return(CASE); }
126 "char"         { count(); return(CHAR); }
127 "code"         { count(); TKEYWORD(CODE); }
128 "const"        { count(); return(CONST); }
129 "continue"     { count(); return(CONTINUE); }
130 "critical"     { count(); TKEYWORD(CRITICAL); } 
131 "data"         { count(); TKEYWORD(DATA);   }
132 "default"      { count(); return(DEFAULT); }
133 "do"           { count(); return(DO); }
134 "double"       { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
135 "else"         { count(); return(ELSE); }
136 "enum"         { count(); return(ENUM); }
137 "extern"       { count(); return(EXTERN); }
138 "far"          { count(); TKEYWORD(XDATA);  }
139 "eeprom"       { count(); TKEYWORD(EEPROM);  }
140 "float"        { count(); return(FLOAT); }
141 "flash"        { count(); TKEYWORD(CODE);}
142 "for"          { count(); return(FOR); }
143 "goto"         { count(); return(GOTO); }
144 "idata"        { count(); TKEYWORD(IDATA);}
145 "if"           { count(); return(IF); }
146 "int"          { count(); return(INT); }
147 "interrupt"    { count(); return(INTERRUPT);}
148 "nonbanked"    { count(); TKEYWORD(NONBANKED);}
149 "banked"       { count(); TKEYWORD(BANKED);}
150 "long"         { count(); return(LONG); }
151 "near"         { count(); TKEYWORD(DATA);}
152 "pdata"        { count(); TKEYWORD(PDATA); }
153 "reentrant"    { count(); TKEYWORD(REENTRANT);}
154 "register"     { count(); return(REGISTER); }
155 "return"       { count(); return(RETURN); }
156 "sfr"          { count(); TKEYWORD(SFR) ; }
157 "sbit"         { count(); TKEYWORD(SBIT)        ; }
158 "short"        { count(); return(SHORT); }
159 "signed"       { count(); return(SIGNED); }
160 "sizeof"       { count(); return(SIZEOF); }
161 "sram"         { count(); TKEYWORD(XDATA);}
162 "static"       { count(); return(STATIC); }
163 "struct"       { count(); return(STRUCT); }
164 "switch"       { count(); return(SWITCH); }
165 "typedef"      { count(); return(TYPEDEF); }
166 "union"        { count(); return(UNION); }
167 "unsigned"     { count(); return(UNSIGNED); }
168 "void"         { count(); return(VOID); }
169 "volatile"     { count(); return(VOLATILE); }
170 "using"        { count(); TKEYWORD(USING); }
171 "_naked"       { count(); TKEYWORD(NAKED); }
172 "while"        { count(); return(WHILE); }
173 "xdata"        { count(); TKEYWORD(XDATA); }
174 "..."          { count(); return(VAR_ARGS);}
175 "__typeof"     { count(); return TYPEOF;}
176 "_JavaNative"  { count(); TKEYWORD(JAVANATIVE);}
177 "_overlay"     { count(); TKEYWORD(OVERLAY);}
178 {L}({L}|{D})*  { count(); return(check_type()); }
179 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
180 0{D}+{IS}?     { count(); yylval.val = constVal(yytext); return(CONSTANT); }
181 {D}+{IS}?      { count(); yylval.val = constVal(yytext); return(CONSTANT); }
182 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); /* ' make syntax highliter happy */}
183 {D}+{E}{FS}?   { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
184 {D}*"."{D}+({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
185 {D}+"."{D}*({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
186 \"             { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
187 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
188 "<<=" { count(); yylval.yyint = LEFT_ASSIGN  ; return(LEFT_ASSIGN) ; }
189 "+="  { count(); yylval.yyint = ADD_ASSIGN   ; return(ADD_ASSIGN)  ; }
190 "-="  { count(); yylval.yyint = SUB_ASSIGN   ; return(SUB_ASSIGN)  ; }
191 "*="  { count(); yylval.yyint = MUL_ASSIGN   ; return(MUL_ASSIGN)  ; }
192 "/="  { count(); yylval.yyint = DIV_ASSIGN   ; return(DIV_ASSIGN)  ; }
193 "%="  { count(); yylval.yyint = MOD_ASSIGN   ; return(MOD_ASSIGN)  ; }
194 "&="  { count(); yylval.yyint = AND_ASSIGN   ; return(AND_ASSIGN)  ; }
195 "^="  { count(); yylval.yyint = XOR_ASSIGN   ; return(XOR_ASSIGN)  ; }
196 "|="  { count(); yylval.yyint = OR_ASSIGN    ; return(OR_ASSIGN)   ; }
197 ">>"           { count(); return(RIGHT_OP); }
198 "<<"           { count(); return(LEFT_OP); }
199 "++"           { count(); return(INC_OP); }
200 "--"           { count(); return(DEC_OP); }
201 "->"           { count(); return(PTR_OP); }
202 "&&"           { count(); return(AND_OP); }
203 "||"           { count(); return(OR_OP); }
204 "<="           { count(); return(LE_OP); }
205 ">="           { count(); return(GE_OP); }
206 "=="           { count(); return(EQ_OP); }
207 "!="           { count(); return(NE_OP); }
208 ";"            { count(); return(';'); }
209 "{"            { count(); NestLevel++ ;  return('{'); }
210 "}"            { count(); NestLevel--; return('}'); }
211 ","            { count(); return(','); }
212 ":"            { count(); return(':'); }
213 "="            { count(); return('='); }
214 "("            { count(); return('('); }
215 ")"            { count(); return(')'); }
216 "["            { count(); return('['); }
217 "]"            { count(); return(']'); }
218 "."            { count(); return('.'); }
219 "&"            { count(); return('&'); }
220 "!"            { count(); return('!'); }
221 "~"            { count(); return('~'); }
222 "-"            { count(); return('-'); }
223 "+"            { count(); return('+'); }
224 "*"            { count(); return('*'); }
225 "/"            { count(); return('/'); }
226 "%"            { count(); return('%'); }
227 "<"            { count(); return('<'); }
228 ">"            { count(); return('>'); }
229 "^"            { count(); return('^'); }
230 "|"            { count(); return('|'); }
231 "?"            { count(); return('?'); }
232 ^#line.*"\n"       { count(); checkCurrFile(yytext); }
233 ^#pragma.*"\n"   { count(); process_pragma(yytext); }
234
235 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
236 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
237 "\r\n"             { count(); }
238 "\n"               { count(); }
239 [ \t\v\f]      { count(); }
240 \\ {
241   char ch=input();
242   if (ch!='\n') {
243     // that could have been removed by the preprocessor anyway
244     werror (W_STRAY_BACKSLASH, column);
245     unput(ch);
246   }
247 }
248 .                          { count()    ; }
249 %%
250
251 int checkCurrFile ( char *s)
252 {
253     char lineNum[10]                    ;
254     int  lNum                           ;
255     char *tptr                          ;
256        
257     /* first check if this is a #line */
258     if ( strncmp(s,"#line",5) )
259         return  0                               ;
260     
261     /* get to the line number */
262     while (!isdigit(*s))
263         s++ ;
264     tptr = lineNum ;
265     while (isdigit(*s))
266         *tptr++ = *s++ ;
267     *tptr = '\0'; 
268     sscanf(lineNum,"%d",&lNum);
269     
270     /* now see if we have a file name */
271     while (*s != '\"' && *s) 
272         s++ ;
273     
274     /* if we don't have a filename then */
275     /* set the current line number to   */
276     /* line number if printFlag is on   */
277     if (!*s) {          
278       lineno = yylineno = lNum ;
279       return 0;
280     }
281     
282     /* if we have a filename then check */
283     /* if it is "standard in" if yes then */
284     /* get the currentfile name info    */
285     s++ ;
286
287     /* in c1mode fullSrcFileName is NULL */
288     if ( fullSrcFileName &&
289          strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
290       lineno = yylineno = lNum;                                 
291       currFname = fullSrcFileName ;
292     }  else {
293         char *sb = s;
294         /* mark the end of the filename */
295         while (*s != '"') s++;
296         *s = '\0';
297         currFname = strdup (sb);
298         lineno = yylineno = lNum;
299     }
300     filename = currFname ;
301     return 0;
302 }
303     
304 int column = 0;
305 int plineIdx=0;
306
307 void count()
308 {
309   int i;
310   for (i = 0; yytext[i] != '\0'; i++)   {                               
311     if (yytext[i] == '\n')      {         
312       column = 0;
313       lineno = ++yylineno ;
314     }
315     else 
316       if (yytext[i] == '\t')
317         column += 8 - (column % 8);
318       else
319         column++;
320   }
321   /* ECHO; */
322 }
323
324 int check_type()
325 {
326         /* check if it is in the typedef table */
327         if (findSym(TypedefTab,NULL,yytext)) {
328                 strncpyz(yylval.yychar,yytext, SDCC_NAME_MAX);
329                 return (TYPE_NAME) ;
330         }
331         else   {
332                 strncpyz (yylval.yychar,yytext, SDCC_NAME_MAX);
333                 return(IDENTIFIER);
334         }
335 }
336
337 char strLitBuff[2048]; // TODO: this is asking for the next bug :)
338
339 /*
340  * Change by JTV 2001-05-19 to not concantenate strings
341  * to support ANSI hex and octal escape sequences in string liteals 
342  */
343
344 char *stringLiteral () {
345   int ch;
346   char *str = strLitBuff;
347   
348   *str++ = '\"';
349   /* put into the buffer till we hit the first \" */
350   
351   while (1) {
352     ch = input();
353     
354     if (!ch)
355       break; /* end of input */
356     
357     /* if it is a \ then escape char's are allowed */
358     if (ch == '\\') {
359       ch=input();
360       if (ch=='\n') {
361         /* \<newline> is a continuator */
362         lineno=++yylineno;
363         column=0;
364         continue;
365       }
366       *str++ = '\\'; /* backslash in place */
367       *str++ = ch; /* get the escape char, no further check */
368       continue; /* carry on */
369     }
370     
371     /* if new line we have a new line break, which is illegal */
372     if (ch == '\n') {
373       werror (W_NEWLINE_IN_STRING);
374       *str++ = '\n';
375       lineno=++yylineno;
376       column=0;
377       continue;
378     }
379     
380     /* if this is a quote then we have work to do */
381     /* find the next non whitespace character     */
382     /* if that is a double quote then carry on    */
383     if (ch == '\"') {
384       *str++  = ch ; /* Pass end of this string or substring to evaluator */
385       while ((ch = input()) && (isspace(ch) || ch=='\\')) {
386         switch (ch) {
387         case '\\':
388           if ((ch=input())!='\n') {
389             werror (W_STRAY_BACKSLASH, column);
390             unput(ch);
391           } else {
392             lineno=++yylineno;
393             column=0;
394           }
395           break;
396         case '\n':
397           yylineno++;
398           break;
399         }
400       }
401
402       if (!ch) 
403         break; 
404
405       if (ch != '\"') {
406         unput(ch) ;
407         break ;
408       }
409     }
410     *str++  = ch; /* Put next substring introducer into output string */
411   }  
412   *str = '\0';
413   
414   /* If we aren't going to fix it, at least trap it. */
415   if (strlen(strLitBuff) >= sizeof(strLitBuff))
416   {
417         fprintf(stderr, "Internal error: strLitBuff overflowed.\n");
418         exit(-1);
419   }
420   
421   return strLitBuff;
422 }
423
424 void doPragma (int op, char *cp)
425 {
426     switch (op) {
427     case P_SAVE:
428         memcpy(&save_options,&options,sizeof(options));
429         memcpy(&save_optimize,&optimize,sizeof(optimize));
430         break;
431     case P_RESTORE:
432         memcpy(&options,&save_options,sizeof(options));
433         memcpy(&optimize,&save_optimize,sizeof(optimize));
434         break;
435     case P_NOINDUCTION:
436         optimize.loopInduction = 0 ;
437         break;
438     case P_NOINVARIANT:
439         optimize.loopInvariant = 0 ;
440         break;
441     case P_INDUCTION:
442         optimize.loopInduction = 1 ;
443         break;
444     case P_STACKAUTO:
445         options.stackAuto = 1;
446         break;
447     case P_NOJTBOUND:
448         optimize.noJTabBoundary = 1;
449         break;
450     case P_NOGCSE:
451         optimize.global_cse = 0;
452         break;
453     case P_NOOVERLAY:
454         options.noOverlay = 1;
455         break;
456     case P_CALLEE_SAVES:
457         {
458             int i=0;
459             /* append to the functions already listed
460                in callee-saves */
461             for (; options.calleeSaves[i] ;i++);
462             parseWithComma(&options.calleeSaves[i], Safe_strdup(cp));
463         }
464         break;
465     case P_EXCLUDE:
466         parseWithComma(options.excludeRegs, Safe_strdup(cp));
467         break;
468     case P_NOIV:
469         options.noiv = 1;
470         break;
471     case P_LOOPREV:
472         optimize.noLoopReverse = 1;
473         break;
474     case P_OVERLAY_:
475         break; /* notyet */
476     }
477 }
478
479 int process_pragma(char *s)
480 {
481     char *cp ;
482     /* find the pragma */
483     while (strncmp(s,"#pragma",7))
484         s++;
485     s += 7;
486     
487     /* look for the directive */
488     while(isspace(*s)) s++;
489
490     cp = s;
491     /* look for the end of the directive */
492     while ((! isspace(*s)) && 
493            (*s != '\n')) 
494         s++ ;    
495
496     /* First give the port a chance */
497     if (port->process_pragma && !port->process_pragma(cp))
498         return 0;
499
500     /* now compare and do what needs to be done */
501     if (strncmp(cp,PRAGMA_SAVE,strlen(PRAGMA_SAVE)) == 0) {
502         doPragma(P_SAVE,cp+strlen(PRAGMA_SAVE));
503         return 0;
504     }
505
506     if (strncmp(cp,PRAGMA_RESTORE,strlen(PRAGMA_RESTORE)) == 0) {
507         doPragma (P_RESTORE,cp+strlen(PRAGMA_RESTORE));
508         return 0;
509     }
510
511     if (strncmp(cp,PRAGMA_NOINDUCTION,strlen(PRAGMA_NOINDUCTION)) == 0) {
512         doPragma (P_NOINDUCTION,cp+strlen(PRAGMA_NOINDUCTION))  ;
513         return 0;
514     }
515
516     if (strncmp(cp,PRAGMA_NOINVARIANT,strlen(PRAGMA_NOINVARIANT)) == 0) {
517         doPragma (P_NOINVARIANT,NULL)   ;
518         return 0;
519     }
520
521     if (strncmp(cp,PRAGMA_INDUCTION,strlen(PRAGMA_INDUCTION)) == 0) {
522         doPragma (P_INDUCTION,NULL)     ;
523         return 0;
524     }
525
526     if (strncmp(cp,PRAGMA_STACKAUTO,strlen(PRAGMA_STACKAUTO)) == 0) {
527         doPragma (P_STACKAUTO,NULL);
528         return 0;
529     }
530
531     if (strncmp(cp,PRAGMA_NOJTBOUND,strlen(PRAGMA_NOJTBOUND)) == 0) {
532         doPragma (P_NOJTBOUND,NULL);
533         return 0;
534     }
535
536     if (strncmp(cp,PRAGMA_NOGCSE,strlen(PRAGMA_NOGCSE)) == 0) {
537         doPragma (P_NOGCSE,NULL);
538         return 0;
539     }
540
541     if (strncmp(cp,PRAGMA_NOOVERLAY,strlen(PRAGMA_NOOVERLAY)) == 0) {
542         doPragma (P_NOOVERLAY,NULL);
543         return 0;
544     }
545     
546     if (strncmp(cp,PRAGMA_CALLEESAVES,strlen(PRAGMA_CALLEESAVES)) == 0) {
547         doPragma(P_CALLEE_SAVES,cp+strlen(PRAGMA_CALLEESAVES));
548         return 0;
549     }
550     
551     if (strncmp(cp,PRAGMA_EXCLUDE,strlen(PRAGMA_EXCLUDE)) == 0) {
552         doPragma(P_EXCLUDE,cp+strlen(PRAGMA_EXCLUDE));
553         return 0;
554     }
555
556     if (strncmp(cp,PRAGMA_NOIV,strlen(PRAGMA_NOIV)) == 0) {
557         doPragma(P_NOIV,cp+strlen(PRAGMA_NOIV));
558         return 0;
559     }
560
561     if (strncmp(cp,PRAGMA_NOLOOPREV,strlen(PRAGMA_NOLOOPREV)) == 0) {
562         doPragma(P_LOOPREV,NULL);
563         return 0;
564     }
565
566     werror(W_UNKNOWN_PRAGMA,cp);
567     return 0;
568 }
569
570 /* will return 1 if the string is a part
571    of a target specific keyword */
572 int isTargetKeyword(char *s)
573 {
574     int i;
575     
576     if (port->keywords == NULL)
577         return 0;
578     for ( i = 0 ; port->keywords[i] ; i++ ) {
579         if (strcmp(port->keywords[i],s) == 0)
580             return 1;
581     }
582     
583     return 0;
584 }
585
586 extern int fatalError;
587
588 int yyerror(char *s)
589 {
590    fflush(stdout);
591
592    if (yylineno && filename) {
593      fprintf(stdout,"\n%s:%d: %s: token -> '%s' ; column %d\n",
594              filename,yylineno,
595              s,yytext,column);
596      fatalError++;
597    } else {
598      // this comes from an empy file, no problem
599    }
600    return 0;
601 }