error.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/common/error.h>
  6. #include <aws/common/common.h>
  7. #include <errno.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. static AWS_THREAD_LOCAL int tl_last_error = 0;
  11. static aws_error_handler_fn *s_global_handler = NULL;
  12. static void *s_global_error_context = NULL;
  13. static AWS_THREAD_LOCAL aws_error_handler_fn *tl_thread_handler = NULL;
  14. AWS_THREAD_LOCAL void *tl_thread_handler_context = NULL;
  15. /* Since slot size is 00000100 00000000, to divide, we need to shift right by 10
  16. * bits to find the slot, and to find the modulus, we use a binary and with
  17. * 00000011 11111111 to find the index in that slot.
  18. */
  19. #define SLOT_MASK (AWS_ERROR_ENUM_STRIDE - 1)
  20. static const int MAX_ERROR_CODE = AWS_ERROR_ENUM_STRIDE * AWS_PACKAGE_SLOTS;
  21. static const struct aws_error_info_list *volatile ERROR_SLOTS[AWS_PACKAGE_SLOTS] = {0};
  22. int aws_last_error(void) {
  23. return tl_last_error;
  24. }
  25. static const struct aws_error_info *get_error_by_code(int err) {
  26. if (err >= MAX_ERROR_CODE || err < 0) {
  27. return NULL;
  28. }
  29. uint32_t slot_index = (uint32_t)err >> AWS_ERROR_ENUM_STRIDE_BITS;
  30. uint32_t error_index = (uint32_t)err & SLOT_MASK;
  31. const struct aws_error_info_list *error_slot = ERROR_SLOTS[slot_index];
  32. if (!error_slot || error_index >= error_slot->count) {
  33. return NULL;
  34. }
  35. return &error_slot->error_list[error_index];
  36. }
  37. const char *aws_error_str(int err) {
  38. const struct aws_error_info *error_info = get_error_by_code(err);
  39. if (error_info) {
  40. return error_info->error_str;
  41. }
  42. return "Unknown Error Code";
  43. }
  44. const char *aws_error_name(int err) {
  45. const struct aws_error_info *error_info = get_error_by_code(err);
  46. if (error_info) {
  47. return error_info->literal_name;
  48. }
  49. return "Unknown Error Code";
  50. }
  51. const char *aws_error_lib_name(int err) {
  52. const struct aws_error_info *error_info = get_error_by_code(err);
  53. if (error_info) {
  54. return error_info->lib_name;
  55. }
  56. return "Unknown Error Code";
  57. }
  58. const char *aws_error_debug_str(int err) {
  59. const struct aws_error_info *error_info = get_error_by_code(err);
  60. if (error_info) {
  61. return error_info->formatted_name;
  62. }
  63. return "Unknown Error Code";
  64. }
  65. void aws_raise_error_private(int err) {
  66. tl_last_error = err;
  67. if (tl_thread_handler) {
  68. tl_thread_handler(tl_last_error, tl_thread_handler_context);
  69. } else if (s_global_handler) {
  70. s_global_handler(tl_last_error, s_global_error_context);
  71. }
  72. }
  73. void aws_reset_error(void) {
  74. tl_last_error = 0;
  75. }
  76. void aws_restore_error(int err) {
  77. tl_last_error = err;
  78. }
  79. aws_error_handler_fn *aws_set_global_error_handler_fn(aws_error_handler_fn *handler, void *ctx) {
  80. aws_error_handler_fn *old_handler = s_global_handler;
  81. s_global_handler = handler;
  82. s_global_error_context = ctx;
  83. return old_handler;
  84. }
  85. aws_error_handler_fn *aws_set_thread_local_error_handler_fn(aws_error_handler_fn *handler, void *ctx) {
  86. aws_error_handler_fn *old_handler = tl_thread_handler;
  87. tl_thread_handler = handler;
  88. tl_thread_handler_context = ctx;
  89. return old_handler;
  90. }
  91. void aws_register_error_info(const struct aws_error_info_list *error_info) {
  92. /*
  93. * We're not so worried about these asserts being removed in an NDEBUG build
  94. * - we'll either segfault immediately (for the first two) or for the count
  95. * assert, the registration will be ineffective.
  96. */
  97. AWS_FATAL_ASSERT(error_info);
  98. AWS_FATAL_ASSERT(error_info->error_list);
  99. AWS_FATAL_ASSERT(error_info->count);
  100. const int min_range = error_info->error_list[0].error_code;
  101. const int slot_index = min_range >> AWS_ERROR_ENUM_STRIDE_BITS;
  102. if (slot_index >= AWS_PACKAGE_SLOTS || slot_index < 0) {
  103. /* This is an NDEBUG build apparently. Kill the process rather than
  104. * corrupting heap. */
  105. fprintf(stderr, "Bad error slot index %d\n", slot_index);
  106. AWS_FATAL_ASSERT(false);
  107. }
  108. #if DEBUG_BUILD
  109. /* Assert that first error has the right value */
  110. const int expected_first_code = slot_index << AWS_ERROR_ENUM_STRIDE_BITS;
  111. if (error_info->error_list[0].error_code != expected_first_code) {
  112. fprintf(
  113. stderr,
  114. "Missing info: First error in list should be %d, not %d (%s)\n",
  115. expected_first_code,
  116. error_info->error_list[0].error_code,
  117. error_info->error_list[0].literal_name);
  118. AWS_FATAL_ASSERT(0);
  119. }
  120. /* Assert that error info entries are in the right order. */
  121. for (int i = 0; i < error_info->count; ++i) {
  122. const int expected_code = min_range + i;
  123. const struct aws_error_info *info = &error_info->error_list[i];
  124. if (info->error_code != expected_code) {
  125. if (info->error_code) {
  126. fprintf(stderr, "Error %s is at wrong index of error info list.\n", info->literal_name);
  127. } else {
  128. fprintf(stderr, "Error %d is missing from error info list.\n", expected_code);
  129. }
  130. AWS_FATAL_ASSERT(0);
  131. }
  132. }
  133. #endif /* DEBUG_BUILD */
  134. ERROR_SLOTS[slot_index] = error_info;
  135. }
  136. void aws_unregister_error_info(const struct aws_error_info_list *error_info) {
  137. AWS_FATAL_ASSERT(error_info);
  138. AWS_FATAL_ASSERT(error_info->error_list);
  139. AWS_FATAL_ASSERT(error_info->count);
  140. const int min_range = error_info->error_list[0].error_code;
  141. const int slot_index = min_range >> AWS_ERROR_ENUM_STRIDE_BITS;
  142. if (slot_index >= AWS_PACKAGE_SLOTS || slot_index < 0) {
  143. /* This is an NDEBUG build apparently. Kill the process rather than
  144. * corrupting heap. */
  145. fprintf(stderr, "Bad error slot index %d\n", slot_index);
  146. AWS_FATAL_ASSERT(0);
  147. }
  148. ERROR_SLOTS[slot_index] = NULL;
  149. }
  150. int aws_translate_and_raise_io_error(int error_no) {
  151. switch (error_no) {
  152. case EINVAL:
  153. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  154. case ESPIPE:
  155. return aws_raise_error(AWS_ERROR_STREAM_UNSEEKABLE);
  156. case EPERM:
  157. case EACCES:
  158. return aws_raise_error(AWS_ERROR_NO_PERMISSION);
  159. case EISDIR:
  160. case ENAMETOOLONG:
  161. case ENOENT:
  162. case ENOTDIR:
  163. return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
  164. case EMFILE:
  165. case ENFILE:
  166. return aws_raise_error(AWS_ERROR_MAX_FDS_EXCEEDED);
  167. case ENOMEM:
  168. return aws_raise_error(AWS_ERROR_OOM);
  169. case ENOSPC:
  170. return aws_raise_error(AWS_ERROR_NO_SPACE);
  171. case ENOTEMPTY:
  172. return aws_raise_error(AWS_ERROR_DIRECTORY_NOT_EMPTY);
  173. default:
  174. return aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE);
  175. }
  176. }