Kernel/libc - Fixed memory clobbering when vsnprintf output is bigger than buffer
[tpg/acess2.git] / KernelLand / Kernel / libc.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * libc.c
6  * - Kernel-land C Library
7  */
8 #include <acess.h>
9 #include <hal_proc.h>   // For MM_*
10 #include <utf16.h>
11
12 // === CONSTANTS ===
13 #define RANDOM_SEED     0xACE55052
14 #define RANDOM_A        0x00731ADE
15 #define RANDOM_C        12345
16 #define RANDOM_SPRUCE   0xf12b039
17
18 // === PROTOTYPES ===
19 #if 0
20 unsigned long long      strtoull(const char *str, char **end, int base);
21 unsigned long   strtoul(const char *str, char **end, int base);
22 signed long long        strtoll(const char *str, char **end, int base);
23 signed long     strtol(const char *str, char **end, int base);
24  int    atoi(const char *string);
25  int    ParseInt(const char *string, int *Val);
26 void    itoa(char *buf, Uint64 num, int base, int minLength, char pad);
27  int    vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
28  int    snprintf(char *__s, size_t __n, const char *__format, ...);
29  int    sprintf(char *__s, const char *__format, ...);
30  int    strucmp(const char *Str1, const char *Str2);
31 char    *strchr(const char *__s, int __c);
32  int    strpos(const char *Str, char Ch);
33 size_t  strlen(const char *__s);
34 char    *strcpy(char *__str1, const char *__str2);
35 char    *strncpy(char *__str1, const char *__str2, size_t max);
36 char    *strcat(char *dest, const char *source);
37  int    strcmp(const char *str1, const char *str2);
38  int    strncmp(const char *str1, const char *str2, size_t num);
39 char    *_strdup(const char *File, int Line, const char *Str);
40  int    rand(void);
41 void    *memmove(void *__dest, const void *__src, size_t len);
42
43  int    CheckString(char *String);
44  int    CheckMem(void *Mem, int NumBytes); 
45 #endif
46
47 // === EXPORTS ===
48 EXPORT(atoi);
49 EXPORT(itoa);
50 EXPORT(vsnprintf);
51 EXPORT(snprintf);
52 EXPORT(sprintf);
53 EXPORT(tolower);
54
55 EXPORT(strucmp);
56 EXPORT(strchr);
57 EXPORT(strrchr);
58 EXPORT(strpos);
59 EXPORT(strlen);
60 EXPORT(strcpy);
61 EXPORT(strncpy);
62 EXPORT(strcat);
63 EXPORT(strncat);
64 EXPORT(strcmp);
65 EXPORT(strncmp);
66 //EXPORT(strdup);
67 EXPORT(_strdup);        // Takes File/Line too
68 EXPORT(rand);
69 EXPORT(memmove);
70
71 EXPORT(CheckString);
72 EXPORT(CheckMem);
73
74 // === CODE ===
75 // - Import userland stroi.c file
76 #define _LIB_H_
77 #include "../../Usermode/Libraries/libc.so_src/strtoi.c"
78
79 int ParseInt(const char *string, int *Val)
80 {
81          int    ret = 0;
82          int    bNeg = 0;
83         const char *orig_string = string;
84         
85         //Log("atoi: (string='%s')", string);
86         
87         // Clear non-numeric characters
88         while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
89         if( *string == '-' ) {
90                 bNeg = 1;
91                 while( !('0' <= *string && *string <= '9') )    string++;
92         }
93         
94         if(*string == '0')
95         {
96                 string ++;
97                 if(*string == 'x')
98                 {
99                         // Hex
100                         string ++;
101                         for( ;; string ++ )
102                         {
103                                 if('0' <= *string && *string <= '9') {
104                                         ret *= 16;
105                                         ret += *string - '0';
106                                 }
107                                 else if('A' <= *string && *string <= 'F') {
108                                         ret *= 16;
109                                         ret += *string - 'A' + 10;
110                                 }
111                                 else if('a' <= *string && *string <= 'f') {
112                                         ret *= 16;
113                                         ret += *string - 'a' + 10;
114                                 }
115                                 else
116                                         break;
117                         }
118                 }
119                 else    // Octal
120                 {
121                         for( ; '0' <= *string && *string <= '7'; string ++ )
122                         {
123                                 ret *= 8;
124                                 ret += *string - '0';
125                         }
126                 }
127         }
128         else    // Decimal
129         {
130                 for( ; '0' <= *string && *string <= '9'; string++)
131                 {
132                         ret *= 10;
133                         ret += *string - '0';
134                 }
135                 // Error check
136                 if( ret == 0 )  return 0;
137         }
138         
139         if(bNeg)        ret = -ret;
140         
141         //Log("atoi: RETURN %i", ret);
142         
143         if(Val) *Val = ret;
144         
145         return string - orig_string;
146 }
147
148 static const char cUCDIGITS[] = "0123456789ABCDEF";
149 /**
150  * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
151  * \brief Convert an integer into a character string
152  */
153 void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
154 {
155         char    tmpBuf[64+1];
156          int    pos=0, i;
157         Uint64  rem;
158
159         // Sanity check
160         if(!buf)        return;
161         
162         // Sanity Check
163         if(base > 16 || base < 2) {
164                 buf[0] = 0;
165                 return;
166         }
167         
168         // Convert 
169         while(num > base-1) {
170                 num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
171                 ASSERT(rem >= 0);
172                 ASSERT(rem < base);
173                 tmpBuf[pos] = cUCDIGITS[ rem ];
174                 pos++;
175         }
176         tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
177         
178         // Put in reverse
179         i = 0;
180         minLength -= pos;
181         while(minLength-- > 0)  buf[i++] = pad;
182         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
183         buf[i] = 0;
184 }
185
186 /**
187  * \brief Append a character the the vsnprintf output
188  */
189 #define PUTCH(ch)       do { \
190                 if(pos < __maxlen && __s) { \
191                         __s[pos] = ch; \
192                 } else { \
193                         (void)ch;\
194                 } \
195                 pos ++; \
196         } while(0)
197 #define GETVAL()        do {\
198         if(isLongLong)  val = va_arg(args, Uint64);\
199         else    val = va_arg(args, unsigned int);\
200         }while(0)
201 /**
202  * \brief VArg String Number Print Formatted
203  */
204 int vsnprintf(char *__s, const size_t __maxlen, const char *__format, va_list args)
205 {
206         char    c, pad = ' ';
207          int    minSize = 0, precision = -1, len;
208         char    tmpBuf[34];     // For Integers
209         const char      *p = NULL;
210          int    isLongLong = 0, isLong;
211         Uint64  val;
212         size_t  pos = 0;
213         // Flags
214          int    bPadLeft = 0;
215
216         while((c = *__format++) != 0)
217         {
218                 // Non control character
219                 if(c != '%') { PUTCH(c); continue; }
220
221                 c = *__format++;
222                 if(c == '\0')   break;
223                 
224                 // Literal %
225                 if(c == '%') { PUTCH('%'); continue; }
226                 
227                 // Pointer - Done first for debugging
228                 if(c == 'p') {
229                         Uint    ptr = va_arg(args, Uint);
230                         PUTCH('*');     PUTCH('0');     PUTCH('x');
231                         for( len = BITS/4; len -- && ((ptr>>(len*4))&15) == 0; )
232                                 ;
233                         len ++;
234                         if( len == 0 )
235                                 PUTCH( '0' );
236                         else
237                                 while( len -- )
238                                         PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
239                         continue ;
240                 }
241
242                 isLongLong = 0;
243                 isLong = 0;
244         
245                 // - Padding Side Flag
246                 if(c == '-') {
247                         bPadLeft = 1;
248                         c = *__format++;
249                 }
250                 
251                 // - Padding
252                 if(c == '0') {
253                         pad = '0';
254                         c = *__format++;
255                 }
256                 else
257                         pad = ' ';
258                 
259                 // - Minimum length
260                 if(c == '*') {  // Dynamic length
261                         minSize = va_arg(args, unsigned int);
262                         c = *__format++;
263                 }
264                 else if('1' <= c && c <= '9')
265                 {
266                         minSize = 0;
267                         while('0' <= c && c <= '9')
268                         {
269                                 minSize *= 10;
270                                 minSize += c - '0';
271                                 c = *__format++;
272                         }
273                 }
274                 else
275                         minSize = 0;
276                 
277                 // - Precision
278                 precision = -1;
279                 if( c == '.' ) {
280                         c = *__format++;
281                         
282                         if(c == '*') {  // Dynamic length
283                                 precision = va_arg(args, unsigned int);
284                                 c = *__format++;
285                         }
286                         else if('1' <= c && c <= '9')
287                         {
288                                 precision = 0;
289                                 while('0' <= c && c <= '9')
290                                 {
291                                         precision *= 10;
292                                         precision += c - '0';
293                                         c = *__format++;
294                                 }
295                         }
296                 }
297                 
298                 // - Default, Long or LongLong?
299                 isLongLong = 0;
300                 if(c == 'l')    // Long is actually the default on x86
301                 {
302                         isLong = 1;
303                         c = *__format++;
304                         if(c == 'l') {
305                                 c = *__format++;
306                                 isLongLong = 1;
307                         }
308                 }
309                 
310                 // - Now get the format code
311                 p = tmpBuf;
312                 switch(c)
313                 {
314                 case 'd':
315                 case 'i':
316                         GETVAL();
317                         if( isLongLong && val >> 63 ) {
318                                 PUTCH('-');
319                                 val = -val;
320                         }
321                         else if( !isLongLong && val >> 31 ) {
322                                 PUTCH('-');
323                                 val = -(Sint32)val;
324                         }
325                         itoa(tmpBuf, val, 10, minSize, pad);
326                         goto printString;
327                 case 'u':       // Unsigned
328                         GETVAL();
329                         itoa(tmpBuf, val, 10, minSize, pad);
330                         goto printString;
331                 case 'P':       // Physical Address
332                         PUTCH('0');
333                         PUTCH('x');
334                         if(sizeof(tPAddr) > 4)  isLongLong = 1;
335                         GETVAL();
336                         itoa(tmpBuf, val, 16, minSize, pad);
337                         goto printString;
338                 case 'X':       // Hex
339                         if(BITS == 64)
340                                 isLongLong = 1; // TODO: Handle non-x86 64-bit archs
341                         GETVAL();
342                         itoa(tmpBuf, val, 16, minSize, pad);
343                         goto printString;
344                         
345                 case 'x':       // Lower case hex
346                         GETVAL();
347                         itoa(tmpBuf, val, 16, minSize, pad);
348                         goto printString;
349                 case 'o':       // Octal
350                         GETVAL();
351                         itoa(tmpBuf, val, 8, minSize, pad);
352                         goto printString;
353                 case 'b':
354                         GETVAL();
355                         itoa(tmpBuf, val, 2, minSize, pad);
356                         goto printString;
357
358                 case 'B':       //Boolean
359                         val = va_arg(args, unsigned int);
360                         if(val) p = "True";
361                         else    p = "False";
362                         goto printString;
363                 
364                 // String - Null Terminated Array
365                 case 's':
366                         if( isLong ) {
367                                 Uint16  *p16 = va_arg(args, Uint16*);
368                                 Uint8   tmp[5];
369                                 while( *p16 && precision-- ) {
370                                         Uint32  cp;
371                                         p16 += ReadUTF16(p16, &cp);
372                                         tmp[WriteUTF8(tmp, cp)] = 0;
373                                         for(int i = 0; tmp[i] && i<5; i ++)
374                                                 PUTCH(tmp[i]);
375                                 }
376                                 break;
377                         }
378                         p = va_arg(args, char*);        // Get Argument
379                         if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
380                 printString:
381                         if(!p)          p = "(null)";
382                         len = strlen(p);
383                         if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
384                         while(*p && precision--) { PUTCH(*p); p++;} 
385                         if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
386                         break;
387                 
388                 case 'C':       // Non-Null Terminated Character Array
389                         p = va_arg(args, char*);
390                         if( !CheckMem(p, minSize) )     continue;       // No #PFs please
391                         if(!p)  goto printString;
392                         while(minSize--) {
393                                 PUTCH(*p);
394                                 p ++;
395                         }
396                         break;
397                 
398                 // Single Character
399                 case 'c':
400                 default:
401                         GETVAL();
402                         PUTCH( (Uint8)val );
403                         break;
404                 }
405         }
406         
407         if(__s && pos < __maxlen)
408                 __s[pos] = '\0';
409         
410         return pos;
411 }
412 #undef PUTCH
413
414 /**
415  */
416 int snprintf(char *__s, size_t __n, const char *__format, ...)
417 {
418         va_list args;
419          int    ret;
420         
421         va_start(args, __format);
422         ret = vsnprintf(__s, __n, __format, args);
423         va_end(args);
424         
425         return ret;
426 }
427
428 /**
429  */
430 int sprintf(char *__s, const char *__format, ...)
431 {
432         va_list args;
433          int    ret;
434         
435         va_start(args, __format);
436         ret = vsnprintf(__s, -1, __format, args);
437         va_end(args);
438         
439         return ret;
440 }
441
442 /*
443  * ==================
444  * ctype.h
445  * ==================
446  */
447 int isalnum(int c)
448 {
449         return isalpha(c) || isdigit(c);
450 }
451 int isalpha(int c)
452 {
453         return isupper(c) || islower(c);
454 }
455 int isascii(int c)
456 {
457         return (0 <= c && c < 128);
458 }
459 int isblank(int c)
460 {
461         if(c == '\t')   return 1;
462         if(c == ' ')    return 1;
463         return 0;
464 }
465 int iscntrl(int c)
466 {
467         // TODO: Check iscntrl
468         if(c < ' ')     return 1;
469         return 0;
470 }
471 int isdigit(int c)
472 {
473         return ('0' <= c && c <= '9');
474 }
475 int isgraph(int c)
476 {
477         // TODO: Check isgraph
478         return 0;
479 }
480 int islower(int c)
481 {
482         return ('a' <= c && c <= 'z');
483 }
484 int isprint(int c)
485 {
486         if( ' ' <= c && c <= 0x7F )     return 1;
487         return 0;
488 }
489 int ispunct(int c)
490 {
491         switch(c)
492         {
493         case '.':       case ',':
494         case '?':       case '!':
495                 return 1;
496         default:
497                 return 0;
498         }
499 }
500 int isspace(int c)
501 {
502         if(c == ' ')    return 1;
503         if(c == '\t')   return 1;
504         if(c == '\v')   return 1;
505         if(c == '\n')   return 1;
506         if(c == '\r')   return 1;
507         return 0;
508 }
509 int isupper(int c)
510 {
511         return ('A' <= c && c <= 'Z');
512 }
513 int isxdigit(int c)
514 {
515         return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
516 }
517
518 int toupper(int c)
519 {
520         if( islower(c) )
521                 return c - 0x20;
522         else
523                 return c;
524 }
525 int tolower(int c)
526 {
527         if( isupper(c) )
528                 return c + 0x20;
529         else
530                 return c;
531 }
532
533 /**
534  * \fn int strucmp(const char *Str1, const char *Str2)
535  * \brief Compare \a Str1 and \a Str2 case-insensitively
536  */
537 int strucmp(const char *Str1, const char *Str2)
538 {
539         while(*Str1 && tolower(*Str1) == tolower(*Str2))
540                 Str1++, Str2++;
541         return tolower(*Str1) - tolower(*Str2);
542 }
543
544 /**
545  * \brief Locate a byte in a string
546  */
547 char *strchr(const char *__s, int __c)
548 {
549         for( ; *__s; __s ++ )
550         {
551                 if( *__s == __c )       return (char*)__s;
552         }
553         return NULL;
554 }
555
556 char *strrchr(const char *__s, int __c)
557 {
558         size_t ofs = strlen(__s);
559         while(--ofs && __s[ofs] != __c);
560         if( __s[ofs] == __c )
561                 return (char*)__s + ofs;
562         return NULL;
563 }
564
565 /**
566  * \fn int strpos(const char *Str, char Ch)
567  * \brief Search a string for an ascii character
568  */
569 int strpos(const char *Str, char Ch)
570 {
571          int    pos;
572         for(pos=0;Str[pos];pos++)
573         {
574                 if(Str[pos] == Ch)      return pos;
575         }
576         return -1;
577 }
578
579 /**
580  * \fn size_t strlen(const char *__str)
581  * \brief Get the length of string
582  */
583 size_t strlen(const char *__str)
584 {
585         size_t  ret = 0;
586         while(*__str++) ret++;
587         return ret;
588 }
589
590 /**
591  * \brief Copy a string to a new location
592  */
593 char *strcpy(char *__str1, const char *__str2)
594 {
595         while(*__str2)
596                 *__str1++ = *__str2++;
597         *__str1 = '\0'; // Terminate String
598         return __str1;
599 }
600
601 /**
602  * \brief Copy a string to a new location
603  * \note Copies at most `max` chars
604  */
605 char *strncpy(char *__str1, const char *__str2, size_t __max)
606 {
607         while(*__str2 && __max-- >= 1)
608                 *__str1++ = *__str2++;
609         if(__max)
610                 *__str1 = '\0'; // Terminate String
611         return __str1;
612 }
613
614 /**
615  * \brief Append a string to another
616  */
617 char *strcat(char *__dest, const char *__src)
618 {
619         while(*__dest++);
620         __dest--;
621         while(*__src)
622                 *__dest++ = *__src++;
623         *__dest = '\0';
624         return __dest;
625 }
626
627 /**
628  * \brief Append at most \a n chars to a string from another
629  * \note At most n+1 chars are written (the dest is always zero terminated)
630  */
631 char *strncat(char *__dest, const char *__src, size_t n)
632 {
633         while(*__dest++);
634         while(*__src && n-- >= 1)
635                 *__dest++ = *__src++;
636         *__dest = '\0';
637         return __dest;
638 }
639
640 /**
641  * \fn int strcmp(const char *str1, const char *str2)
642  * \brief Compare two strings return the difference between
643  *        the first non-matching characters.
644  */
645 int strcmp(const char *str1, const char *str2)
646 {
647         while(*str1 && *str1 == *str2)
648                 str1++, str2++;
649         return *str1 - *str2;
650 }
651
652 /**
653  * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
654  * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
655  */
656 int strncmp(const char *Str1, const char *Str2, size_t num)
657 {
658         if(num == 0)    return 0;       // TODO: Check what should officially happen here
659         while(--num && *Str1 && *Str1 == *Str2)
660                 Str1++, Str2++;
661         return *Str1-*Str2;
662 }
663
664 #if 0
665 /**
666  * \fn char *strdup(const char *Str)
667  * \brief Duplicates a string
668  */
669 char *strdup(const char *Str)
670 {
671         char    *ret;
672         ret = malloc(strlen(Str)+1);
673         if( !ret )      return NULL;
674         strcpy(ret, Str);
675         return ret;
676 }
677 #else
678
679 /**
680  * \fn char *_strdup(const char *File, int Line, const char *Str)
681  * \brief Duplicates a string
682  */
683 char *_strdup(const char *File, int Line, const char *Str)
684 {
685         char    *ret;
686         ret = Heap_Allocate(File, Line, strlen(Str)+1);
687         if( !ret )      return NULL;
688         strcpy(ret, Str);
689         return ret;
690 }
691 #endif
692
693 /**
694  * \fn int rand()
695  * \brief Pseudo random number generator
696  */
697 int rand(void)
698 {
699         #if 0
700         static Uint     state = RANDOM_SEED;
701         Uint    old = state;
702         // Get the next state value
703         giRandomState = (RANDOM_A*state + RANDOM_C);
704         // Check if it has changed, and if it hasn't, change it
705         if(state == old)        state += RANDOM_SPRUCE;
706         return state;
707         #else
708         // http://en.wikipedia.org/wiki/Xorshift
709         // 2010-10-03
710         static Uint32   x = 123456789;
711         static Uint32   y = 362436069;
712         static Uint32   z = 521288629;
713         static Uint32   w = 88675123; 
714         Uint32  t;
715  
716         t = x ^ (x << 11);
717         x = y; y = z; z = w;
718         return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
719         #endif
720 }
721
722 void *memmove(void *__dest, const void *__src, size_t len)
723 {
724         char    *dest = __dest;
725         const char      *src = __src;
726         void    *ret = __dest;
727
728         if( len == 0 || dest == src )
729                 return dest;
730         
731         if( (tVAddr)dest > (tVAddr)src + len )
732                 return memcpy(dest, src, len);
733         if( (tVAddr)dest + len < (tVAddr)src )
734                 return memcpy(dest, src, len);
735         
736         // NOTE: Assumes memcpy works forward
737         if( (tVAddr)dest < (tVAddr)src )
738                 return memcpy(dest, src, len);
739
740         #if 0
741         size_t  block_size;
742         if( (tVAddr)dest < (tVAddr)src )
743                 block_size = (tVAddr)src - (tVAddr)dest;
744         else
745                 block_size = (tVAddr)dest - (tVAddr)src;
746         
747         block_size &= ~0xF;
748         
749         while(len >= block_size)
750         {
751                 memcpy(dest, src, block_size);
752                 len -= block_size;
753                 dest += block_size;
754                 src += block_size;
755         }
756         memcpy(dest, src, len);
757         return ret;
758         #else
759         for( int i = len; i--; )
760         {
761                 dest[i] = src[i];
762         }
763         return ret;
764         #endif
765         
766 }
767
768 // NOTE: Strictly not libc, but lib.c is used by userland code too and hence these two
769 // can't be in it.
770 /**
771  * \name Memory Validation
772  * \{
773  */
774 /**
775  * \brief Checks if a string resides fully in valid memory
776  */
777 int CheckString(const char *String)
778 {
779         tVAddr  addr;
780          int    bUser;
781
782         addr = (tVAddr)String;
783
784         if( !MM_GetPhysAddr( (void*)addr ) )
785                 return 0;
786         
787         // Check 1st page
788         bUser = MM_IsUser( addr );
789         
790         while( *(char*)addr )
791         {
792                 if( (addr & (PAGE_SIZE-1)) == 0 )
793                 {
794                         if(bUser && !MM_IsUser(addr) )
795                                 return 0;
796                         if(!bUser && !MM_GetPhysAddr((void*)addr) )
797                                 return 0;
798                 }
799                 addr ++;
800         }
801         return 1;
802 }
803
804 /**
805  * \brief Check if a sized memory region is valid memory
806  * \return Boolean success
807  */
808 int CheckMem(const void *Mem, int NumBytes)
809 {
810         return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
811 }
812 /* *
813  * \}
814  */
815

UCC git Repository :: git.ucc.asn.au