cxa_atexit.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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 <stdint.h>
  17. #include <libc-lock.h>
  18. #include "exit.h"
  19. #include <sysdep.h>
  20. #undef __cxa_atexit
  21. /* See concurrency notes in stdlib/exit.h where this lock is declared. */
  22. __libc_lock_define_initialized (, __exit_funcs_lock)
  23. int
  24. attribute_hidden
  25. __internal_atexit (void (*func) (void *), void *arg, void *d,
  26. struct exit_function_list **listp)
  27. {
  28. struct exit_function *new;
  29. /* As a QoI issue we detect NULL early with an assertion instead
  30. of a SIGSEGV at program exit when the handler is run (bug 20544). */
  31. assert (func != NULL);
  32. __libc_lock_lock (__exit_funcs_lock);
  33. new = __new_exitfn (listp);
  34. if (new == NULL)
  35. {
  36. __libc_lock_unlock (__exit_funcs_lock);
  37. return -1;
  38. }
  39. #ifdef PTR_MANGLE
  40. PTR_MANGLE (func);
  41. #endif
  42. new->func.cxa.fn = (void (*) (void *, int)) func;
  43. new->func.cxa.arg = arg;
  44. new->func.cxa.dso_handle = d;
  45. new->flavor = ef_cxa;
  46. __libc_lock_unlock (__exit_funcs_lock);
  47. return 0;
  48. }
  49. /* Register a function to be called by exit or when a shared library
  50. is unloaded. This function is only called from code generated by
  51. the C++ compiler. */
  52. int
  53. __cxa_atexit (void (*func) (void *), void *arg, void *d)
  54. {
  55. return __internal_atexit (func, arg, d, &__exit_funcs);
  56. }
  57. libc_hidden_def (__cxa_atexit)
  58. static struct exit_function_list initial;
  59. struct exit_function_list *__exit_funcs = &initial;
  60. uint64_t __new_exitfn_called;
  61. /* Must be called with __exit_funcs_lock held. */
  62. struct exit_function *
  63. __new_exitfn (struct exit_function_list **listp)
  64. {
  65. struct exit_function_list *p = NULL;
  66. struct exit_function_list *l;
  67. struct exit_function *r = NULL;
  68. size_t i = 0;
  69. if (__exit_funcs_done)
  70. /* Exit code is finished processing all registered exit functions,
  71. therefore we fail this registration. */
  72. return NULL;
  73. for (l = *listp; l != NULL; p = l, l = l->next)
  74. {
  75. for (i = l->idx; i > 0; --i)
  76. if (l->fns[i - 1].flavor != ef_free)
  77. break;
  78. if (i > 0)
  79. break;
  80. /* This block is completely unused. */
  81. l->idx = 0;
  82. }
  83. if (l == NULL || i == sizeof (l->fns) / sizeof (l->fns[0]))
  84. {
  85. /* The last entry in a block is used. Use the first entry in
  86. the previous block if it exists. Otherwise create a new one. */
  87. if (p == NULL)
  88. {
  89. assert (l != NULL);
  90. p = (struct exit_function_list *)
  91. calloc (1, sizeof (struct exit_function_list));
  92. if (p != NULL)
  93. {
  94. p->next = *listp;
  95. *listp = p;
  96. }
  97. }
  98. if (p != NULL)
  99. {
  100. r = &p->fns[0];
  101. p->idx = 1;
  102. }
  103. }
  104. else
  105. {
  106. /* There is more room in the block. */
  107. r = &l->fns[i];
  108. l->idx = i + 1;
  109. }
  110. /* Mark entry as used, but we don't know the flavor now. */
  111. if (r != NULL)
  112. {
  113. r->flavor = ef_us;
  114. ++__new_exitfn_called;
  115. }
  116. return r;
  117. }