1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 /* 8 * k5-platform.h 9 * 10 * Copyright 2003, 2004, 2005 Massachusetts Institute of Technology. 11 * All Rights Reserved. 12 * 13 * Export of this software from the United States of America may 14 * require a specific license from the United States Government. 15 * It is the responsibility of any person or organization contemplating 16 * export to obtain such a license before exporting. 17 * 18 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 19 * distribute this software and its documentation for any purpose and 20 * without fee is hereby granted, provided that the above copyright 21 * notice appear in all copies and that both that copyright notice and 22 * this permission notice appear in supporting documentation, and that 23 * the name of M.I.T. not be used in advertising or publicity pertaining 24 * to distribution of the software without specific, written prior 25 * permission. Furthermore if you modify this software you must label 26 * your software as modified software and not distribute it in such a 27 * fashion that it might be confused with the original M.I.T. software. 28 * M.I.T. makes no representations about the suitability of 29 * this software for any purpose. It is provided "as is" without express 30 * or implied warranty. 31 * 32 * 33 * Some platform-dependent definitions to sync up the C support level. 34 * Some to a C99-ish level, some related utility code. 35 * 36 * Currently: 37 * + make "static inline" work 38 * + 64-bit types and load/store code 39 * + SIZE_MAX 40 * + shared library init/fini hooks 41 * + consistent getpwnam/getpwuid interfaces 42 */ 43 44 #ifndef K5_PLATFORM_H 45 #define K5_PLATFORM_H 46 47 /* Solaris Kerberos */ 48 #ifndef _KERNEL 49 #include <sys/types.h> 50 51 #include "autoconf.h" 52 53 /* Initialization and finalization function support for libraries. 54 55 At top level, before the functions are defined or even declared: 56 MAKE_INIT_FUNCTION(init_fn); 57 MAKE_FINI_FUNCTION(fini_fn); 58 Then: 59 int init_fn(void) { ... } 60 void fini_fn(void) { if (INITIALIZER_RAN(init_fn)) ... } 61 In code, in the same file: 62 err = CALL_INIT_FUNCTION(init_fn); 63 64 To trigger or verify the initializer invocation from another file, 65 a helper function must be created. 66 67 This model handles both the load-time execution (Windows) and 68 delayed execution (pthread_once) approaches, and should be able to 69 guarantee in both cases that the init function is run once, in one 70 thread, before other stuff in the library is done; furthermore, the 71 finalization code should only run if the initialization code did. 72 (Maybe I could've made the "if INITIALIZER_RAN" test implicit, via 73 another function hidden in macros, but this is hairy enough 74 already.) 75 76 The init_fn and fini_fn names should be chosen such that any 77 exported names staring with those names, and optionally followed by 78 additional characters, fits in with any namespace constraints on 79 the library in question. 80 81 82 There's also PROGRAM_EXITING() currently always defined as zero. 83 If there's some trivial way to find out if the fini function is 84 being called because the program that the library is linked into is 85 exiting, we can just skip all the work because the resources are 86 about to be freed up anyways. Generally this is likely to be the 87 same as distinguishing whether the library was loaded dynamically 88 while the program was running, or loaded as part of program 89 startup. On most platforms, I don't think we can distinguish these 90 cases easily, and it's probably not worth expending any significant 91 effort. (Note in particular that atexit() won't do, because if the 92 library is explicitly loaded and unloaded, it would have to be able 93 to deregister the atexit callback function. Also, the system limit 94 on atexit callbacks may be small.) 95 96 97 Implementation outline: 98 99 Windows: MAKE_FINI_FUNCTION creates a symbol with a magic name that 100 is sought at library build time, and code is added to invoke the 101 function when the library is unloaded. MAKE_INIT_FUNCTION does 102 likewise, but the function is invoked when the library is loaded, 103 and an extra variable is declared to hold an error code and a "yes 104 the initializer ran" flag. CALL_INIT_FUNCTION blows up if the flag 105 isn't set, otherwise returns the error code. 106 107 UNIX: MAKE_INIT_FUNCTION creates and initializes a variable with a 108 name derived from the function name, containing a k5_once_t 109 (pthread_once_t or int), an error code, and a pointer to the 110 function. The function itself is declared static, but the 111 associated variable has external linkage. CALL_INIT_FUNCTION 112 ensures thath the function is called exactly once (pthread_once or 113 just check the flag) and returns the stored error code (or the 114 pthread_once error). 115 116 (That's the basic idea. With some debugging assert() calls and 117 such, it's a bit more complicated. And we also need to handle 118 doing the pthread test at run time on systems where that works, so 119 we use the k5_once_t stuff instead.) 120 121 UNIX, with compiler support: MAKE_FINI_FUNCTION declares the 122 function as a destructor, and the run time linker support or 123 whatever will cause it to be invoked when the library is unloaded, 124 the program ends, etc. 125 126 UNIX, with linker support: MAKE_FINI_FUNCTION creates a symbol with 127 a magic name that is sought at library build time, and linker 128 options are used to mark it as a finalization function for the 129 library. The symbol must be exported. 130 131 UNIX, no library finalization support: The finalization function 132 never runs, and we leak memory. Tough. 133 134 DELAY_INITIALIZER will be defined by the configure script if we 135 want to use k5_once instead of load-time initialization. That'll 136 be the preferred method on most systems except Windows, where we 137 have to initialize some mutexes. 138 139 140 141 142 For maximum flexibility in defining the macros, the function name 143 parameter should be a simple name, not even a macro defined as 144 another name. The function should have a unique name, and should 145 conform to whatever namespace is used by the library in question. 146 (We do have export lists, but (1) they're not used for all 147 platforms, and (2) they're not used for static libraries.) 148 149 If the macro expansion needs the function to have been declared, it 150 must include a declaration. If it is not necessary for the symbol 151 name to be exported from the object file, the macro should declare 152 it as "static". Hence the signature must exactly match "void 153 foo(void)". (ANSI C allows a static declaration followed by a 154 non-static one; the result is internal linkage.) The macro 155 expansion has to come before the function, because gcc apparently 156 won't act on "__attribute__((constructor))" if it comes after the 157 function definition. 158 159 This is going to be compiler- and environment-specific, and may 160 require some support at library build time, and/or "asm" 161 statements. But through macro expansion and auxiliary functions, 162 we should be able to handle most things except #pragma. 163 164 It's okay for this code to require that the library be built 165 with the same compiler and compiler options throughout, but 166 we shouldn't require that the library and application use the 167 same compiler. 168 169 For static libraries, we don't really care about cleanup too much, 170 since it's all memory handling and mutex allocation which will all 171 be cleaned up when the program exits. Thus, it's okay if gcc-built 172 static libraries don't play nicely with cc-built executables when 173 it comes to static constructors, just as long as it doesn't cause 174 linking to fail. 175 176 For dynamic libraries on UNIX, we'll use pthread_once-type support 177 to do delayed initialization, so if finalization can't be made to 178 work, we'll only have memory leaks in a load/use/unload cycle. If 179 anyone (like, say, the OS vendor) complains about this, they can 180 tell us how to get a shared library finalization function invoked 181 automatically. 182 183 Currently there's --disable-delayed-initialization for preventing 184 the initialization from being delayed on UNIX, but that's mainly 185 just for testing the linker options for initialization, and will 186 probably be removed at some point. */ 187 188 /* Helper macros. */ 189 190 # define JOIN__2_2(A,B) A ## _ ## _ ## B 191 # define JOIN__2(A,B) JOIN__2_2(A,B) 192 193 /* XXX Should test USE_LINKER_INIT_OPTION early, and if it's set, 194 always provide a function by the expected name, even if we're 195 delaying initialization. */ 196 197 #if defined(DELAY_INITIALIZER) 198 199 /* Run the initialization code during program execution, at the latest 200 possible moment. This means multiple threads may be active. */ 201 # include "k5-thread.h" 202 typedef struct { k5_once_t once; int error, did_run; void (*fn)(void); } k5_init_t; 203 # ifdef USE_LINKER_INIT_OPTION 204 # define MAYBE_DUMMY_INIT(NAME) \ 205 void JOIN__2(NAME, auxinit) () { } 206 # else 207 # define MAYBE_DUMMY_INIT(NAME) 208 # endif 209 # ifdef __GNUC__ 210 /* Do it in macro form so we get the file/line of the invocation if 211 the assertion fails. */ 212 # define k5_call_init_function(I) \ 213 (__extension__ ({ \ 214 k5_init_t *k5int_i = (I); \ 215 int k5int_err = k5_once(&k5int_i->once, k5int_i->fn); \ 216 (k5int_err \ 217 ? k5int_err \ 218 : (assert(k5int_i->did_run != 0), k5int_i->error)); \ 219 })) 220 # define MAYBE_DEFINE_CALLINIT_FUNCTION 221 # else 222 # define MAYBE_DEFINE_CALLINIT_FUNCTION \ 223 static int k5_call_init_function(k5_init_t *i) \ 224 { \ 225 int err; \ 226 err = k5_once(&i->once, i->fn); \ 227 if (err) \ 228 return err; \ 229 assert (i->did_run != 0); \ 230 return i->error; \ 231 } 232 # endif 233 # define MAKE_INIT_FUNCTION(NAME) \ 234 static int NAME(void); \ 235 MAYBE_DUMMY_INIT(NAME) \ 236 /* forward declaration for use in initializer */ \ 237 static void JOIN__2(NAME, aux) (void); \ 238 static k5_init_t JOIN__2(NAME, once) = \ 239 { K5_ONCE_INIT, 0, 0, JOIN__2(NAME, aux) }; \ 240 MAYBE_DEFINE_CALLINIT_FUNCTION \ 241 static void JOIN__2(NAME, aux) (void) \ 242 { \ 243 JOIN__2(NAME, once).did_run = 1; \ 244 JOIN__2(NAME, once).error = NAME(); \ 245 } \ 246 /* so ';' following macro use won't get error */ \ 247 static int NAME(void) 248 # define CALL_INIT_FUNCTION(NAME) \ 249 k5_call_init_function(& JOIN__2(NAME, once)) 250 /* This should be called in finalization only, so we shouldn't have 251 multiple active threads mucking around in our library at this 252 point. So ignore the once_t object and just look at the flag. 253 254 XXX Could we have problems with memory coherence between processors 255 if we don't invoke mutex/once routines? Probably not, the 256 application code should already be coordinating things such that 257 the library code is not in use by this point, and memory 258 synchronization will be needed there. */ 259 # define INITIALIZER_RAN(NAME) \ 260 (JOIN__2(NAME, once).did_run && JOIN__2(NAME, once).error == 0) 261 262 # define PROGRAM_EXITING() (0) 263 264 #elif defined(__GNUC__) && !defined(_WIN32) && defined(CONSTRUCTOR_ATTR_WORKS) 265 266 /* Run initializer at load time, via GCC/C++ hook magic. */ 267 268 # ifdef USE_LINKER_INIT_OPTION 269 /* Both gcc and linker option?? Favor gcc. */ 270 # define MAYBE_DUMMY_INIT(NAME) \ 271 void JOIN__2(NAME, auxinit) () { } 272 # else 273 # define MAYBE_DUMMY_INIT(NAME) 274 # endif 275 276 typedef struct { int error; unsigned char did_run; } k5_init_t; 277 # define MAKE_INIT_FUNCTION(NAME) \ 278 MAYBE_DUMMY_INIT(NAME) \ 279 static k5_init_t JOIN__2(NAME, ran) \ 280 = { 0, 2 }; \ 281 static void JOIN__2(NAME, aux)(void) \ 282 __attribute__((constructor)); \ 283 static int NAME(void); \ 284 static void JOIN__2(NAME, aux)(void) \ 285 { \ 286 JOIN__2(NAME, ran).error = NAME(); \ 287 JOIN__2(NAME, ran).did_run = 3; \ 288 } \ 289 static int NAME(void) 290 # define CALL_INIT_FUNCTION(NAME) \ 291 (JOIN__2(NAME, ran).did_run == 3 \ 292 ? JOIN__2(NAME, ran).error \ 293 : (abort(),0)) 294 # define INITIALIZER_RAN(NAME) (JOIN__2(NAME,ran).did_run == 3 && JOIN__2(NAME, ran).error == 0) 295 296 # define PROGRAM_EXITING() (0) 297 298 #elif defined(USE_LINKER_INIT_OPTION) || defined(_WIN32) 299 300 /* Run initializer at load time, via linker magic, or in the 301 case of WIN32, win_glue.c hard-coded knowledge. */ 302 typedef struct { int error; unsigned char did_run; } k5_init_t; 303 # define MAKE_INIT_FUNCTION(NAME) \ 304 static k5_init_t JOIN__2(NAME, ran) \ 305 = { 0, 2 }; \ 306 static int NAME(void); \ 307 void JOIN__2(NAME, auxinit)() \ 308 { \ 309 JOIN__2(NAME, ran).error = NAME(); \ 310 JOIN__2(NAME, ran).did_run = 3; \ 311 } \ 312 static int NAME(void) 313 # define CALL_INIT_FUNCTION(NAME) \ 314 (JOIN__2(NAME, ran).did_run == 3 \ 315 ? JOIN__2(NAME, ran).error \ 316 : (abort(),0)) 317 # define INITIALIZER_RAN(NAME) \ 318 (JOIN__2(NAME, ran).error == 0) 319 320 # define PROGRAM_EXITING() (0) 321 322 #else 323 324 # error "Don't know how to do load-time initializers for this configuration." 325 326 # define PROGRAM_EXITING() (0) 327 328 #endif 329 330 331 332 #if defined(USE_LINKER_FINI_OPTION) || defined(_WIN32) 333 /* If we're told the linker option will be used, it doesn't really 334 matter what compiler we're using. Do it the same way 335 regardless. */ 336 337 # ifdef __hpux 338 339 /* On HP-UX, we need this auxiliary function. At dynamic load or 340 unload time (but *not* program startup and termination for 341 link-time specified libraries), the linker-indicated function 342 is called with a handle on the library and a flag indicating 343 whether it's being loaded or unloaded. 344 345 The "real" fini function doesn't need to be exported, so 346 declare it static. 347 348 As usual, the final declaration is just for syntactic 349 convenience, so the top-level invocation of this macro can be 350 followed by a semicolon. */ 351 352 # include <dl.h> 353 # define MAKE_FINI_FUNCTION(NAME) \ 354 static void NAME(void); \ 355 void JOIN__2(NAME, auxfini)(shl_t, int); /* silence gcc warnings */ \ 356 void JOIN__2(NAME, auxfini)(shl_t h, int l) { if (!l) NAME(); } \ 357 static void NAME(void) 358 359 # else /* not hpux */ 360 361 # define MAKE_FINI_FUNCTION(NAME) \ 362 void NAME(void) 363 364 # endif 365 366 #elif defined(__GNUC__) && defined(DESTRUCTOR_ATTR_WORKS) 367 /* If we're using gcc, if the C++ support works, the compiler should 368 build executables and shared libraries that support the use of 369 static constructors and destructors. The C compiler supports a 370 function attribute that makes use of the same facility as C++. 371 372 XXX How do we know if the C++ support actually works? */ 373 # define MAKE_FINI_FUNCTION(NAME) \ 374 static void NAME(void) __attribute__((destructor)) 375 376 #elif !defined(SHARED) 377 378 /* In this case, we just don't care about finalization. 379 380 The code will still define the function, but we won't do anything 381 with it. Annoying: This may generate unused-function warnings. */ 382 383 # define MAKE_FINI_FUNCTION(NAME) \ 384 static void NAME(void) 385 386 #else 387 388 # error "Don't know how to do unload-time finalization for this configuration." 389 390 #endif 391 392 #endif /* !_KERNEL */ 393 394 395 /* 64-bit support: krb5_ui_8 and krb5_int64. 396 397 This should move to krb5.h eventually, but without the namespace 398 pollution from the autoconf macros. */ 399 #if defined(HAVE_STDINT_H) || defined(HAVE_INTTYPES_H) 400 # ifdef HAVE_STDINT_H 401 # include <stdint.h> 402 # endif 403 # ifdef HAVE_INTTYPES_H 404 # include <inttypes.h> 405 # endif 406 # define INT64_TYPE int64_t 407 # define UINT64_TYPE uint64_t 408 #elif defined(_WIN32) 409 # define INT64_TYPE signed __int64 410 # define UINT64_TYPE unsigned __int64 411 #else /* not Windows, and neither stdint.h nor inttypes.h */ 412 # define INT64_TYPE signed long long 413 # define UINT64_TYPE unsigned long long 414 #endif 415 416 #ifndef _KERNEL 417 #include <limits.h> 418 #endif /* !_KERNEL */ 419 #ifndef SIZE_MAX 420 # define SIZE_MAX ((size_t)((size_t)0 - 1)) 421 #endif 422 423 424 /* Read and write integer values as (unaligned) octet strings in 425 specific byte orders. 426 427 Add per-platform optimizations later if needed. (E.g., maybe x86 428 unaligned word stores and gcc/asm instructions for byte swaps, 429 etc.) */ 430 431 /* Solaris Kerberos: To avoid problems with lint the following 432 functions can be found in separate header files. */ 433 #if 0 434 static void 435 store_16_be (unsigned int val, unsigned char *p) 436 { 437 p[0] = (val >> 8) & 0xff; 438 p[1] = (val ) & 0xff; 439 } 440 static void 441 store_16_le (unsigned int val, unsigned char *p) 442 { 443 p[1] = (val >> 8) & 0xff; 444 p[0] = (val ) & 0xff; 445 } 446 static void 447 store_32_be (unsigned int val, unsigned char *p) 448 { 449 p[0] = (val >> 24) & 0xff; 450 p[1] = (val >> 16) & 0xff; 451 p[2] = (val >> 8) & 0xff; 452 p[3] = (val ) & 0xff; 453 } 454 static void 455 store_32_le (unsigned int val, unsigned char *p) 456 { 457 p[3] = (val >> 24) & 0xff; 458 p[2] = (val >> 16) & 0xff; 459 p[1] = (val >> 8) & 0xff; 460 p[0] = (val ) & 0xff; 461 } 462 static void 463 store_64_be (UINT64_TYPE val, unsigned char *p) 464 { 465 p[0] = (unsigned char)((val >> 56) & 0xff); 466 p[1] = (unsigned char)((val >> 48) & 0xff); 467 p[2] = (unsigned char)((val >> 40) & 0xff); 468 p[3] = (unsigned char)((val >> 32) & 0xff); 469 p[4] = (unsigned char)((val >> 24) & 0xff); 470 p[5] = (unsigned char)((val >> 16) & 0xff); 471 p[6] = (unsigned char)((val >> 8) & 0xff); 472 p[7] = (unsigned char)((val ) & 0xff); 473 } 474 static void 475 store_64_le (UINT64_TYPE val, unsigned char *p) 476 { 477 p[7] = (unsigned char)((val >> 56) & 0xff); 478 p[6] = (unsigned char)((val >> 48) & 0xff); 479 p[5] = (unsigned char)((val >> 40) & 0xff); 480 p[4] = (unsigned char)((val >> 32) & 0xff); 481 p[3] = (unsigned char)((val >> 24) & 0xff); 482 p[2] = (unsigned char)((val >> 16) & 0xff); 483 p[1] = (unsigned char)((val >> 8) & 0xff); 484 p[0] = (unsigned char)((val ) & 0xff); 485 } 486 static unsigned short 487 load_16_be (unsigned char *p) 488 { 489 return (p[1] | (p[0] << 8)); 490 } 491 static unsigned short 492 load_16_le (unsigned char *p) 493 { 494 return (p[0] | (p[1] << 8)); 495 } 496 static unsigned int 497 load_32_be (unsigned char *p) 498 { 499 return (p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24)); 500 } 501 static unsigned int 502 load_32_le (unsigned char *p) 503 { 504 return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); 505 } 506 static UINT64_TYPE 507 load_64_be (unsigned char *p) 508 { 509 return ((UINT64_TYPE)load_32_be(p) << 32) | load_32_be(p+4); 510 } 511 static UINT64_TYPE 512 load_64_le (unsigned char *p) 513 { 514 return ((UINT64_TYPE)load_32_le(p+4) << 32) | load_32_le(p); 515 } 516 #endif 517 518 /* Make the interfaces to getpwnam and getpwuid consistent. 519 Model the wrappers on the POSIX thread-safe versions, but 520 use the unsafe system versions if the safe ones don't exist 521 or we can't figure out their interfaces. */ 522 /* SUNW15resync - just have Solaris relevant ones */ 523 524 #define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \ 525 (*(OUT) = getpwnam_r(NAME,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0) 526 527 #define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \ 528 (*(OUT) = getpwuid_r(UID,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0) 529 530 /* Return true if the snprintf return value RESULT reflects a buffer 531 overflow for the buffer size SIZE. 532 533 We cast the result to unsigned int for two reasons. First, old 534 implementations of snprintf (such as the one in Solaris 9 and 535 prior) return -1 on a buffer overflow. Casting the result to -1 536 will convert that value to UINT_MAX, which should compare larger 537 than any reasonable buffer size. Second, comparing signed and 538 unsigned integers will generate warnings with some compilers, and 539 can have unpredictable results, particularly when the relative 540 widths of the types is not known (size_t may be the same width as 541 int or larger). 542 */ 543 #define SNPRINTF_OVERFLOW(result, size) \ 544 ((unsigned int)(result) >= (size_t)(size)) 545 546 #endif /* K5_PLATFORM_H */ 547