cxa_finalize.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /* Copyright (C) 1999-2019 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, see
  13. <http://www.gnu.org/licenses/>. */
  14. #include <assert.h>
  15. #include <stdlib.h>
  16. #include "exit.h"
  17. #include <fork.h>
  18. #include <sysdep.h>
  19. #include <stdint.h>
  20. /* If D is non-NULL, call all functions registered with `__cxa_atexit'
  21. with the same dso handle. Otherwise, if D is NULL, call all of the
  22. registered handlers. */
  23. void
  24. __cxa_finalize (void *d)
  25. {
  26. struct exit_function_list *funcs;
  27. __libc_lock_lock (__exit_funcs_lock);
  28. restart:
  29. for (funcs = __exit_funcs; funcs; funcs = funcs->next)
  30. {
  31. struct exit_function *f;
  32. for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
  33. if ((d == NULL || d == f->func.cxa.dso_handle) && f->flavor == ef_cxa)
  34. {
  35. const uint64_t check = __new_exitfn_called;
  36. void (*cxafn) (void *arg, int status) = f->func.cxa.fn;
  37. void *cxaarg = f->func.cxa.arg;
  38. /* We don't want to run this cleanup more than once. The Itanium
  39. C++ ABI requires that multiple calls to __cxa_finalize not
  40. result in calling termination functions more than once. One
  41. potential scenario where that could happen is with a concurrent
  42. dlclose and exit, where the running dlclose must at some point
  43. release the list lock, an exiting thread may acquire it, and
  44. without setting flavor to ef_free, might re-run this destructor
  45. which could result in undefined behaviour. Therefore we must
  46. set flavor to ef_free to avoid calling this destructor again.
  47. Note that the concurrent exit must also take the dynamic loader
  48. lock (for library finalizer processing) and therefore will
  49. block while dlclose completes the processing of any in-progress
  50. exit functions. Lastly, once we release the list lock for the
  51. entry marked ef_free, we must not read from that entry again
  52. since it may have been reused by the time we take the list lock
  53. again. Lastly the detection of new registered exit functions is
  54. based on a monotonically incrementing counter, and there is an
  55. ABA if between the unlock to run the exit function and the
  56. re-lock after completion the user registers 2^64 exit functions,
  57. the implementation will not detect this and continue without
  58. executing any more functions.
  59. One minor issue remains: A registered exit function that is in
  60. progress by a call to dlclose() may not completely finish before
  61. the next registered exit function is run. This may, according to
  62. some readings of POSIX violate the requirement that functions
  63. run in effective LIFO order. This should probably be fixed in a
  64. future implementation to ensure the functions do not run in
  65. parallel. */
  66. f->flavor = ef_free;
  67. #ifdef PTR_DEMANGLE
  68. PTR_DEMANGLE (cxafn);
  69. #endif
  70. /* Unlock the list while we call a foreign function. */
  71. __libc_lock_unlock (__exit_funcs_lock);
  72. cxafn (cxaarg, 0);
  73. __libc_lock_lock (__exit_funcs_lock);
  74. /* It is possible that that last exit function registered
  75. more exit functions. Start the loop over. */
  76. if (__glibc_unlikely (check != __new_exitfn_called))
  77. goto restart;
  78. }
  79. }
  80. /* Also remove the quick_exit handlers, but do not call them. */
  81. for (funcs = __quick_exit_funcs; funcs; funcs = funcs->next)
  82. {
  83. struct exit_function *f;
  84. for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
  85. if (d == NULL || d == f->func.cxa.dso_handle)
  86. f->flavor = ef_free;
  87. }
  88. /* Remove the registered fork handlers. We do not have to
  89. unregister anything if the program is going to terminate anyway. */
  90. #ifdef UNREGISTER_ATFORK
  91. if (d != NULL)
  92. UNREGISTER_ATFORK (d);
  93. #endif
  94. __libc_lock_unlock (__exit_funcs_lock);
  95. }