tst-allocate_once.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /* Test the allocate_once function.
  2. Copyright (C) 2018-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <allocate_once.h>
  16. #include <mcheck.h>
  17. #include <string.h>
  18. #include <support/check.h>
  19. #include <support/support.h>
  20. /* Allocate a new string. */
  21. static void *
  22. allocate_string (void *closure)
  23. {
  24. return xstrdup (closure);
  25. }
  26. /* Allocation and deallocation functions which are not expected to be
  27. called. */
  28. static void *
  29. allocate_not_called (void *closure)
  30. {
  31. FAIL_EXIT1 ("allocation function called unexpectedly (%p)", closure);
  32. }
  33. static void
  34. deallocate_not_called (void *closure, void *ptr)
  35. {
  36. FAIL_EXIT1 ("deallocate function called unexpectedly (%p, %p)",
  37. closure, ptr);
  38. }
  39. /* Counter for various function calls. */
  40. static int function_called;
  41. /* An allocation function which returns NULL and records that it has
  42. been called. */
  43. static void *
  44. allocate_return_null (void *closure)
  45. {
  46. /* The function should only be called once. */
  47. TEST_COMPARE (function_called, 0);
  48. ++function_called;
  49. return NULL;
  50. }
  51. /* The following is used to check the retry logic, by causing a fake
  52. race condition. */
  53. static void *fake_race_place;
  54. static char fake_race_region[3]; /* To obtain unique addresses. */
  55. static void *
  56. fake_race_allocate (void *closure)
  57. {
  58. TEST_VERIFY (closure == &fake_race_region[0]);
  59. TEST_COMPARE (function_called, 0);
  60. ++function_called;
  61. /* Fake allocation by another thread. */
  62. fake_race_place = &fake_race_region[1];
  63. return &fake_race_region[2];
  64. }
  65. static void
  66. fake_race_deallocate (void *closure, void *ptr)
  67. {
  68. /* Check that the pointer returned from fake_race_allocate is
  69. deallocated (and not the one stored in fake_race_place). */
  70. TEST_VERIFY (ptr == &fake_race_region[2]);
  71. TEST_VERIFY (fake_race_place == &fake_race_region[1]);
  72. TEST_VERIFY (closure == &fake_race_region[0]);
  73. TEST_COMPARE (function_called, 1);
  74. ++function_called;
  75. }
  76. /* Similar to fake_race_allocate, but expects to be paired with free
  77. as the deallocation function. */
  78. static void *
  79. fake_race_allocate_for_free (void *closure)
  80. {
  81. TEST_VERIFY (closure == &fake_race_region[0]);
  82. TEST_COMPARE (function_called, 0);
  83. ++function_called;
  84. /* Fake allocation by another thread. */
  85. fake_race_place = &fake_race_region[1];
  86. return xstrdup ("to be freed");
  87. }
  88. static int
  89. do_test (void)
  90. {
  91. mtrace ();
  92. /* Simple allocation. */
  93. void *place1 = NULL;
  94. char *string1 = allocate_once (&place1, allocate_string,
  95. deallocate_not_called,
  96. (char *) "test string 1");
  97. TEST_VERIFY_EXIT (string1 != NULL);
  98. TEST_VERIFY (strcmp ("test string 1", string1) == 0);
  99. /* Second call returns the first pointer, without calling any
  100. callbacks. */
  101. TEST_VERIFY (string1
  102. == allocate_once (&place1, allocate_not_called,
  103. deallocate_not_called,
  104. (char *) "test string 1a"));
  105. /* Different place should result in another call. */
  106. void *place2 = NULL;
  107. char *string2 = allocate_once (&place2, allocate_string,
  108. deallocate_not_called,
  109. (char *) "test string 2");
  110. TEST_VERIFY_EXIT (string2 != NULL);
  111. TEST_VERIFY (strcmp ("test string 2", string2) == 0);
  112. TEST_VERIFY (string1 != string2);
  113. /* Check error reporting (NULL return value from the allocation
  114. function). */
  115. void *place3 = NULL;
  116. char *string3 = allocate_once (&place3, allocate_return_null,
  117. deallocate_not_called, NULL);
  118. TEST_VERIFY (string3 == NULL);
  119. TEST_COMPARE (function_called, 1);
  120. /* Check that the deallocation function is called if the race is
  121. lost. */
  122. function_called = 0;
  123. TEST_VERIFY (allocate_once (&fake_race_place,
  124. fake_race_allocate,
  125. fake_race_deallocate,
  126. &fake_race_region[0])
  127. == &fake_race_region[1]);
  128. TEST_COMPARE (function_called, 2);
  129. function_called = 3;
  130. TEST_VERIFY (allocate_once (&fake_race_place,
  131. fake_race_allocate,
  132. fake_race_deallocate,
  133. &fake_race_region[0])
  134. == &fake_race_region[1]);
  135. TEST_COMPARE (function_called, 3);
  136. /* Similar, but this time rely on that free is called. */
  137. function_called = 0;
  138. fake_race_place = NULL;
  139. TEST_VERIFY (allocate_once (&fake_race_place,
  140. fake_race_allocate_for_free,
  141. NULL,
  142. &fake_race_region[0])
  143. == &fake_race_region[1]);
  144. TEST_COMPARE (function_called, 1);
  145. function_called = 3;
  146. TEST_VERIFY (allocate_once (&fake_race_place,
  147. fake_race_allocate_for_free,
  148. NULL,
  149. &fake_race_region[0])
  150. == &fake_race_region[1]);
  151. TEST_COMPARE (function_called, 3);
  152. free (place2);
  153. free (place1);
  154. return 0;
  155. }
  156. #include <support/test-driver.c>