error.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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 error info entries are in the right order. */
  110. for (int i = 1; i < error_info->count; ++i) {
  111. const int expected_code = min_range + i;
  112. const struct aws_error_info *info = &error_info->error_list[i];
  113. if (info->error_code != expected_code) {
  114. if (info->error_code) {
  115. fprintf(stderr, "Error %s is at wrong index of error info list.\n", info->literal_name);
  116. } else {
  117. fprintf(stderr, "Error %d is missing from error info list.\n", expected_code);
  118. }
  119. AWS_FATAL_ASSERT(0);
  120. }
  121. }
  122. #endif /* DEBUG_BUILD */
  123. ERROR_SLOTS[slot_index] = error_info;
  124. }
  125. void aws_unregister_error_info(const struct aws_error_info_list *error_info) {
  126. AWS_FATAL_ASSERT(error_info);
  127. AWS_FATAL_ASSERT(error_info->error_list);
  128. AWS_FATAL_ASSERT(error_info->count);
  129. const int min_range = error_info->error_list[0].error_code;
  130. const int slot_index = min_range >> AWS_ERROR_ENUM_STRIDE_BITS;
  131. if (slot_index >= AWS_PACKAGE_SLOTS || slot_index < 0) {
  132. /* This is an NDEBUG build apparently. Kill the process rather than
  133. * corrupting heap. */
  134. fprintf(stderr, "Bad error slot index %d\n", slot_index);
  135. AWS_FATAL_ASSERT(0);
  136. }
  137. ERROR_SLOTS[slot_index] = NULL;
  138. }
  139. int aws_translate_and_raise_io_error(int error_no) {
  140. switch (error_no) {
  141. case EINVAL:
  142. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  143. case ESPIPE:
  144. return aws_raise_error(AWS_ERROR_STREAM_UNSEEKABLE);
  145. case EPERM:
  146. case EACCES:
  147. return aws_raise_error(AWS_ERROR_NO_PERMISSION);
  148. case EISDIR:
  149. case ENAMETOOLONG:
  150. case ENOENT:
  151. return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
  152. case ENFILE:
  153. return aws_raise_error(AWS_ERROR_MAX_FDS_EXCEEDED);
  154. case ENOMEM:
  155. return aws_raise_error(AWS_ERROR_OOM);
  156. case ENOSPC:
  157. return aws_raise_error(AWS_ERROR_NO_SPACE);
  158. default:
  159. return aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE);
  160. }
  161. }