| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | /*++ |
| 6 | |
| 7 | |
| 8 | |
| 9 | Module Name: |
| 10 | |
| 11 | cruntime/misc.cpp |
| 12 | |
| 13 | Abstract: |
| 14 | |
| 15 | Implementation of C runtime functions that don't fit anywhere else. |
| 16 | |
| 17 | |
| 18 | |
| 19 | --*/ |
| 20 | |
| 21 | #include "pal/thread.hpp" |
| 22 | #include "pal/threadsusp.hpp" |
| 23 | #include "pal/palinternal.h" |
| 24 | #include "pal/dbgmsg.h" |
| 25 | #include "pal/misc.h" |
| 26 | |
| 27 | #include <errno.h> |
| 28 | /* <stdarg.h> needs to be included after "palinternal.h" to avoid name |
| 29 | collision for va_start and va_end */ |
| 30 | #include <stdarg.h> |
| 31 | #include <time.h> |
| 32 | #include <limits.h> |
| 33 | |
| 34 | #if defined(_AMD64_) || defined(_x86_) |
| 35 | #include <xmmintrin.h> |
| 36 | #endif // defined(_AMD64_) || defined(_x86_) |
| 37 | #if defined(_DEBUG) |
| 38 | #include <assert.h> |
| 39 | #endif //defined(_DEBUG) |
| 40 | |
| 41 | SET_DEFAULT_DEBUG_CHANNEL(CRT); |
| 42 | |
| 43 | using namespace CorUnix; |
| 44 | |
| 45 | /*++ |
| 46 | Function: |
| 47 | _gcvt_s |
| 48 | |
| 49 | See MSDN doc. |
| 50 | --*/ |
| 51 | char * |
| 52 | __cdecl |
| 53 | _gcvt_s( char * buffer, int iSize, double value, int digits ) |
| 54 | { |
| 55 | PERF_ENTRY(_gcvt); |
| 56 | ENTRY( "_gcvt( value:%f digits=%d, buffer=%p )\n" , value, digits, buffer ); |
| 57 | |
| 58 | if ( !buffer ) |
| 59 | { |
| 60 | ERROR( "buffer was an invalid pointer.\n" ); |
| 61 | } |
| 62 | |
| 63 | switch ( digits ) |
| 64 | { |
| 65 | case 7 : |
| 66 | /* Fall through */ |
| 67 | case 8 : |
| 68 | /* Fall through */ |
| 69 | case 15 : |
| 70 | /* Fall through */ |
| 71 | case 17 : |
| 72 | |
| 73 | sprintf_s( buffer, iSize, "%.*g" , digits, value ); |
| 74 | break; |
| 75 | |
| 76 | default : |
| 77 | ASSERT( "Only the digits 7, 8, 15, and 17 are valid.\n" ); |
| 78 | *buffer = '\0'; |
| 79 | } |
| 80 | |
| 81 | LOGEXIT( "_gcvt returns %p (%s)\n" , buffer , buffer ); |
| 82 | PERF_EXIT(_gcvt); |
| 83 | return buffer; |
| 84 | } |
| 85 | |
| 86 | |
| 87 | /*++ |
| 88 | Function : |
| 89 | |
| 90 | __iscsym |
| 91 | |
| 92 | See MSDN for more details. |
| 93 | --*/ |
| 94 | int |
| 95 | __cdecl |
| 96 | __iscsym( int c ) |
| 97 | { |
| 98 | PERF_ENTRY(__iscsym); |
| 99 | ENTRY( "__iscsym( c=%d )\n" , c ); |
| 100 | |
| 101 | if ( isalnum( c ) || c == '_' ) |
| 102 | { |
| 103 | LOGEXIT( "__iscsym returning 1\n" ); |
| 104 | PERF_EXIT(__iscsym); |
| 105 | return 1; |
| 106 | } |
| 107 | |
| 108 | LOGEXIT( "__iscsym returning 0\n" ); |
| 109 | PERF_EXIT(__iscsym); |
| 110 | return 0; |
| 111 | } |
| 112 | |
| 113 | |
| 114 | /*++ |
| 115 | |
| 116 | Function : |
| 117 | |
| 118 | PAL_errno |
| 119 | |
| 120 | Returns the address of the errno. |
| 121 | |
| 122 | --*/ |
| 123 | int * __cdecl PAL_errno( int caller ) |
| 124 | { |
| 125 | int *retval; |
| 126 | PERF_ENTRY(errno); |
| 127 | ENTRY( "PAL_errno( void )\n" ); |
| 128 | retval = (INT*)(&errno); |
| 129 | LOGEXIT("PAL_errno returns %p\n" ,retval); |
| 130 | PERF_EXIT(errno); |
| 131 | return retval; |
| 132 | } |
| 133 | |
| 134 | /*++ |
| 135 | Function: |
| 136 | |
| 137 | mktime |
| 138 | |
| 139 | See MSDN for more details. |
| 140 | --*/ |
| 141 | |
| 142 | PAL_time_t |
| 143 | __cdecl |
| 144 | PAL_mktime(struct PAL_tm *tm) |
| 145 | { |
| 146 | time_t result; |
| 147 | struct tm tmpTm; |
| 148 | |
| 149 | PERF_ENTRY(mktime); |
| 150 | ENTRY( "mktime( tm=%p )\n" ,tm ); |
| 151 | |
| 152 | /*copy the value of Windows struct into BSD struct*/ |
| 153 | tmpTm.tm_sec = tm->tm_sec; |
| 154 | tmpTm.tm_min = tm->tm_min; |
| 155 | tmpTm.tm_hour = tm->tm_hour; |
| 156 | tmpTm.tm_mday = tm->tm_mday; |
| 157 | tmpTm.tm_mon = tm->tm_mon; |
| 158 | tmpTm.tm_year = tm->tm_year; |
| 159 | tmpTm.tm_wday = tm->tm_wday; |
| 160 | tmpTm.tm_yday = tm->tm_yday; |
| 161 | tmpTm.tm_isdst = tm->tm_isdst; |
| 162 | |
| 163 | result = mktime(&tmpTm); |
| 164 | |
| 165 | LOGEXIT( "mktime returned %#lx\n" ,result ); |
| 166 | PERF_EXIT(mktime); |
| 167 | return result; |
| 168 | } |
| 169 | |
| 170 | /*++ |
| 171 | Function: |
| 172 | |
| 173 | rand |
| 174 | |
| 175 | The RAND_MAX value can vary by platform. |
| 176 | |
| 177 | See MSDN for more details. |
| 178 | --*/ |
| 179 | int |
| 180 | __cdecl |
| 181 | PAL_rand(void) |
| 182 | { |
| 183 | int ret; |
| 184 | PERF_ENTRY(rand); |
| 185 | ENTRY("rand(void)\n" ); |
| 186 | |
| 187 | ret = (rand() % (PAL_RAND_MAX + 1)); |
| 188 | |
| 189 | LOGEXIT("rand() returning %d\n" , ret); |
| 190 | PERF_EXIT(rand); |
| 191 | return ret; |
| 192 | } |
| 193 | |
| 194 | |
| 195 | /*++ |
| 196 | Function: |
| 197 | |
| 198 | time |
| 199 | |
| 200 | See MSDN for more details. |
| 201 | --*/ |
| 202 | PAL_time_t |
| 203 | __cdecl |
| 204 | PAL_time(PAL_time_t *tloc) |
| 205 | { |
| 206 | time_t result; |
| 207 | |
| 208 | PERF_ENTRY(time); |
| 209 | ENTRY( "time( tloc=%p )\n" ,tloc ); |
| 210 | |
| 211 | result = time(tloc); |
| 212 | |
| 213 | LOGEXIT( "time returning %#lx\n" ,result ); |
| 214 | PERF_EXIT(time); |
| 215 | return result; |
| 216 | } |
| 217 | |
| 218 | |
| 219 | PALIMPORT |
| 220 | void __cdecl |
| 221 | PAL_qsort(void *base, size_t nmemb, size_t size, |
| 222 | int (__cdecl *compar )(const void *, const void *)) |
| 223 | { |
| 224 | PERF_ENTRY(qsort); |
| 225 | ENTRY("qsort(base=%p, nmemb=%lu, size=%lu, compar=%p\n" , |
| 226 | base,(unsigned long) nmemb,(unsigned long) size, compar); |
| 227 | |
| 228 | /* reset ENTRY nesting level back to zero, qsort will invoke app-defined |
| 229 | callbacks and we want their entry traces... */ |
| 230 | #if _ENABLE_DEBUG_MESSAGES_ |
| 231 | { |
| 232 | int old_level; |
| 233 | old_level = DBG_change_entrylevel(0); |
| 234 | #endif /* _ENABLE_DEBUG_MESSAGES_ */ |
| 235 | |
| 236 | qsort(base,nmemb,size,compar); |
| 237 | |
| 238 | /* ...and set nesting level back to what it was */ |
| 239 | #if _ENABLE_DEBUG_MESSAGES_ |
| 240 | DBG_change_entrylevel(old_level); |
| 241 | } |
| 242 | #endif /* _ENABLE_DEBUG_MESSAGES_ */ |
| 243 | |
| 244 | LOGEXIT("qsort returns\n" ); |
| 245 | PERF_EXIT(qsort); |
| 246 | } |
| 247 | |
| 248 | PALIMPORT |
| 249 | void * __cdecl |
| 250 | PAL_bsearch(const void *key, const void *base, size_t nmemb, size_t size, |
| 251 | int (__cdecl *compar)(const void *, const void *)) |
| 252 | { |
| 253 | void *retval; |
| 254 | |
| 255 | PERF_ENTRY(bsearch); |
| 256 | ENTRY("bsearch(key=%p, base=%p, nmemb=%lu, size=%lu, compar=%p\n" , |
| 257 | key, base, (unsigned long) nmemb, (unsigned long) size, compar); |
| 258 | |
| 259 | /* reset ENTRY nesting level back to zero, bsearch will invoke app-defined |
| 260 | callbacks and we want their entry traces... */ |
| 261 | #if _ENABLE_DEBUG_MESSAGES_ |
| 262 | { |
| 263 | int old_level; |
| 264 | old_level = DBG_change_entrylevel(0); |
| 265 | #endif /* _ENABLE_DEBUG_MESSAGES_ */ |
| 266 | |
| 267 | retval = bsearch(key,base,nmemb,size,compar); |
| 268 | |
| 269 | /* ...and set nesting level back to what it was */ |
| 270 | #if _ENABLE_DEBUG_MESSAGES_ |
| 271 | DBG_change_entrylevel(old_level); |
| 272 | } |
| 273 | #endif /* _ENABLE_DEBUG_MESSAGES_ */ |
| 274 | |
| 275 | LOGEXIT("bsearch returns %p\n" ,retval); |
| 276 | PERF_EXIT(bsearch); |
| 277 | return retval; |
| 278 | } |
| 279 | |
| 280 | #ifdef _AMD64_ |
| 281 | |
| 282 | PALIMPORT |
| 283 | unsigned int PAL__mm_getcsr(void) |
| 284 | { |
| 285 | return _mm_getcsr(); |
| 286 | } |
| 287 | |
| 288 | PALIMPORT |
| 289 | void PAL__mm_setcsr(unsigned int i) |
| 290 | { |
| 291 | _mm_setcsr(i); |
| 292 | } |
| 293 | |
| 294 | #endif // _AMD64_ |
| 295 | |
| 296 | /*++ |
| 297 | Function: |
| 298 | PAL_memcpy |
| 299 | |
| 300 | Overlapping buffer-safe version of memcpy. |
| 301 | See MSDN doc for memcpy |
| 302 | --*/ |
| 303 | EXTERN_C |
| 304 | PALIMPORT |
| 305 | void *PAL_memcpy (void *dest, const void *src, size_t count) |
| 306 | { |
| 307 | UINT_PTR x = (UINT_PTR)dest, y = (UINT_PTR)src; |
| 308 | _ASSERTE((x + count <= y) || (y + count <= x)); |
| 309 | |
| 310 | void *ret; |
| 311 | #undef memcpy |
| 312 | ret = memcpy(dest, src, count); |
| 313 | return ret; |
| 314 | } |
| 315 | |