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