• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "absl/status/status.h"
15 
16 #include <errno.h>
17 
18 #include <atomic>
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22 #include <memory>
23 #include <ostream>
24 #include <string>
25 
26 #include "absl/base/attributes.h"
27 #include "absl/base/config.h"
28 #include "absl/base/internal/raw_logging.h"
29 #include "absl/base/internal/strerror.h"
30 #include "absl/base/macros.h"
31 #include "absl/base/no_destructor.h"
32 #include "absl/debugging/stacktrace.h"
33 #include "absl/debugging/symbolize.h"
34 #include "absl/status/internal/status_internal.h"
35 #include "absl/strings/str_cat.h"
36 #include "absl/strings/str_format.h"
37 #include "absl/strings/str_split.h"
38 #include "absl/strings/string_view.h"
39 #include "absl/types/optional.h"
40 
41 namespace absl {
42 ABSL_NAMESPACE_BEGIN
43 
44 static_assert(
45     alignof(status_internal::StatusRep) >= 4,
46     "absl::Status assumes it can use the bottom 2 bits of a StatusRep*.");
47 
StatusCodeToString(StatusCode code)48 std::string StatusCodeToString(StatusCode code) {
49   switch (code) {
50     case StatusCode::kOk:
51       return "OK";
52     case StatusCode::kCancelled:
53       return "CANCELLED";
54     case StatusCode::kUnknown:
55       return "UNKNOWN";
56     case StatusCode::kInvalidArgument:
57       return "INVALID_ARGUMENT";
58     case StatusCode::kDeadlineExceeded:
59       return "DEADLINE_EXCEEDED";
60     case StatusCode::kNotFound:
61       return "NOT_FOUND";
62     case StatusCode::kAlreadyExists:
63       return "ALREADY_EXISTS";
64     case StatusCode::kPermissionDenied:
65       return "PERMISSION_DENIED";
66     case StatusCode::kUnauthenticated:
67       return "UNAUTHENTICATED";
68     case StatusCode::kResourceExhausted:
69       return "RESOURCE_EXHAUSTED";
70     case StatusCode::kFailedPrecondition:
71       return "FAILED_PRECONDITION";
72     case StatusCode::kAborted:
73       return "ABORTED";
74     case StatusCode::kOutOfRange:
75       return "OUT_OF_RANGE";
76     case StatusCode::kUnimplemented:
77       return "UNIMPLEMENTED";
78     case StatusCode::kInternal:
79       return "INTERNAL";
80     case StatusCode::kUnavailable:
81       return "UNAVAILABLE";
82     case StatusCode::kDataLoss:
83       return "DATA_LOSS";
84     default:
85       return "";
86   }
87 }
88 
operator <<(std::ostream & os,StatusCode code)89 std::ostream& operator<<(std::ostream& os, StatusCode code) {
90   return os << StatusCodeToString(code);
91 }
92 
EmptyString()93 const std::string* Status::EmptyString() {
94   static const absl::NoDestructor<std::string> kEmpty;
95   return kEmpty.get();
96 }
97 
98 #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
99 constexpr const char Status::kMovedFromString[];
100 #endif
101 
MovedFromString()102 const std::string* Status::MovedFromString() {
103   static const absl::NoDestructor<std::string> kMovedFrom(kMovedFromString);
104   return kMovedFrom.get();
105 }
106 
Status(absl::StatusCode code,absl::string_view msg)107 Status::Status(absl::StatusCode code, absl::string_view msg)
108     : rep_(CodeToInlinedRep(code)) {
109   if (code != absl::StatusCode::kOk && !msg.empty()) {
110     rep_ = PointerToRep(new status_internal::StatusRep(code, msg, nullptr));
111   }
112 }
113 
PrepareToModify(uintptr_t rep)114 status_internal::StatusRep* Status::PrepareToModify(uintptr_t rep) {
115   if (IsInlined(rep)) {
116     return new status_internal::StatusRep(InlinedRepToCode(rep),
117                                           absl::string_view(), nullptr);
118   }
119   return RepToPointer(rep)->CloneAndUnref();
120 }
121 
ToStringSlow(uintptr_t rep,StatusToStringMode mode)122 std::string Status::ToStringSlow(uintptr_t rep, StatusToStringMode mode) {
123   if (IsInlined(rep)) {
124     return absl::StrCat(absl::StatusCodeToString(InlinedRepToCode(rep)), ": ");
125   }
126   return RepToPointer(rep)->ToString(mode);
127 }
128 
operator <<(std::ostream & os,const Status & x)129 std::ostream& operator<<(std::ostream& os, const Status& x) {
130   os << x.ToString(StatusToStringMode::kWithEverything);
131   return os;
132 }
133 
AbortedError(absl::string_view message)134 Status AbortedError(absl::string_view message) {
135   return Status(absl::StatusCode::kAborted, message);
136 }
137 
AlreadyExistsError(absl::string_view message)138 Status AlreadyExistsError(absl::string_view message) {
139   return Status(absl::StatusCode::kAlreadyExists, message);
140 }
141 
CancelledError(absl::string_view message)142 Status CancelledError(absl::string_view message) {
143   return Status(absl::StatusCode::kCancelled, message);
144 }
145 
DataLossError(absl::string_view message)146 Status DataLossError(absl::string_view message) {
147   return Status(absl::StatusCode::kDataLoss, message);
148 }
149 
DeadlineExceededError(absl::string_view message)150 Status DeadlineExceededError(absl::string_view message) {
151   return Status(absl::StatusCode::kDeadlineExceeded, message);
152 }
153 
FailedPreconditionError(absl::string_view message)154 Status FailedPreconditionError(absl::string_view message) {
155   return Status(absl::StatusCode::kFailedPrecondition, message);
156 }
157 
InternalError(absl::string_view message)158 Status InternalError(absl::string_view message) {
159   return Status(absl::StatusCode::kInternal, message);
160 }
161 
InvalidArgumentError(absl::string_view message)162 Status InvalidArgumentError(absl::string_view message) {
163   return Status(absl::StatusCode::kInvalidArgument, message);
164 }
165 
NotFoundError(absl::string_view message)166 Status NotFoundError(absl::string_view message) {
167   return Status(absl::StatusCode::kNotFound, message);
168 }
169 
OutOfRangeError(absl::string_view message)170 Status OutOfRangeError(absl::string_view message) {
171   return Status(absl::StatusCode::kOutOfRange, message);
172 }
173 
PermissionDeniedError(absl::string_view message)174 Status PermissionDeniedError(absl::string_view message) {
175   return Status(absl::StatusCode::kPermissionDenied, message);
176 }
177 
ResourceExhaustedError(absl::string_view message)178 Status ResourceExhaustedError(absl::string_view message) {
179   return Status(absl::StatusCode::kResourceExhausted, message);
180 }
181 
UnauthenticatedError(absl::string_view message)182 Status UnauthenticatedError(absl::string_view message) {
183   return Status(absl::StatusCode::kUnauthenticated, message);
184 }
185 
UnavailableError(absl::string_view message)186 Status UnavailableError(absl::string_view message) {
187   return Status(absl::StatusCode::kUnavailable, message);
188 }
189 
UnimplementedError(absl::string_view message)190 Status UnimplementedError(absl::string_view message) {
191   return Status(absl::StatusCode::kUnimplemented, message);
192 }
193 
UnknownError(absl::string_view message)194 Status UnknownError(absl::string_view message) {
195   return Status(absl::StatusCode::kUnknown, message);
196 }
197 
IsAborted(const Status & status)198 bool IsAborted(const Status& status) {
199   return status.code() == absl::StatusCode::kAborted;
200 }
201 
IsAlreadyExists(const Status & status)202 bool IsAlreadyExists(const Status& status) {
203   return status.code() == absl::StatusCode::kAlreadyExists;
204 }
205 
IsCancelled(const Status & status)206 bool IsCancelled(const Status& status) {
207   return status.code() == absl::StatusCode::kCancelled;
208 }
209 
IsDataLoss(const Status & status)210 bool IsDataLoss(const Status& status) {
211   return status.code() == absl::StatusCode::kDataLoss;
212 }
213 
IsDeadlineExceeded(const Status & status)214 bool IsDeadlineExceeded(const Status& status) {
215   return status.code() == absl::StatusCode::kDeadlineExceeded;
216 }
217 
IsFailedPrecondition(const Status & status)218 bool IsFailedPrecondition(const Status& status) {
219   return status.code() == absl::StatusCode::kFailedPrecondition;
220 }
221 
IsInternal(const Status & status)222 bool IsInternal(const Status& status) {
223   return status.code() == absl::StatusCode::kInternal;
224 }
225 
IsInvalidArgument(const Status & status)226 bool IsInvalidArgument(const Status& status) {
227   return status.code() == absl::StatusCode::kInvalidArgument;
228 }
229 
IsNotFound(const Status & status)230 bool IsNotFound(const Status& status) {
231   return status.code() == absl::StatusCode::kNotFound;
232 }
233 
IsOutOfRange(const Status & status)234 bool IsOutOfRange(const Status& status) {
235   return status.code() == absl::StatusCode::kOutOfRange;
236 }
237 
IsPermissionDenied(const Status & status)238 bool IsPermissionDenied(const Status& status) {
239   return status.code() == absl::StatusCode::kPermissionDenied;
240 }
241 
IsResourceExhausted(const Status & status)242 bool IsResourceExhausted(const Status& status) {
243   return status.code() == absl::StatusCode::kResourceExhausted;
244 }
245 
IsUnauthenticated(const Status & status)246 bool IsUnauthenticated(const Status& status) {
247   return status.code() == absl::StatusCode::kUnauthenticated;
248 }
249 
IsUnavailable(const Status & status)250 bool IsUnavailable(const Status& status) {
251   return status.code() == absl::StatusCode::kUnavailable;
252 }
253 
IsUnimplemented(const Status & status)254 bool IsUnimplemented(const Status& status) {
255   return status.code() == absl::StatusCode::kUnimplemented;
256 }
257 
IsUnknown(const Status & status)258 bool IsUnknown(const Status& status) {
259   return status.code() == absl::StatusCode::kUnknown;
260 }
261 
ErrnoToStatusCode(int error_number)262 StatusCode ErrnoToStatusCode(int error_number) {
263   switch (error_number) {
264     case 0:
265       return StatusCode::kOk;
266     case EINVAL:        // Invalid argument
267     case ENAMETOOLONG:  // Filename too long
268     case E2BIG:         // Argument list too long
269     case EDESTADDRREQ:  // Destination address required
270     case EDOM:          // Mathematics argument out of domain of function
271     case EFAULT:        // Bad address
272     case EILSEQ:        // Illegal byte sequence
273     case ENOPROTOOPT:   // Protocol not available
274     case ENOSTR:        // Not a STREAM
275     case ENOTSOCK:      // Not a socket
276     case ENOTTY:        // Inappropriate I/O control operation
277     case EPROTOTYPE:    // Protocol wrong type for socket
278     case ESPIPE:        // Invalid seek
279       return StatusCode::kInvalidArgument;
280     case ETIMEDOUT:  // Connection timed out
281     case ETIME:      // Timer expired
282       return StatusCode::kDeadlineExceeded;
283     case ENODEV:  // No such device
284     case ENOENT:  // No such file or directory
285 #ifdef ENOMEDIUM
286     case ENOMEDIUM:  // No medium found
287 #endif
288     case ENXIO:  // No such device or address
289     case ESRCH:  // No such process
290       return StatusCode::kNotFound;
291     case EEXIST:         // File exists
292     case EADDRNOTAVAIL:  // Address not available
293     case EALREADY:       // Connection already in progress
294 #ifdef ENOTUNIQ
295     case ENOTUNIQ:  // Name not unique on network
296 #endif
297       return StatusCode::kAlreadyExists;
298     case EPERM:   // Operation not permitted
299     case EACCES:  // Permission denied
300 #ifdef ENOKEY
301     case ENOKEY:  // Required key not available
302 #endif
303     case EROFS:  // Read only file system
304       return StatusCode::kPermissionDenied;
305     case ENOTEMPTY:   // Directory not empty
306     case EISDIR:      // Is a directory
307     case ENOTDIR:     // Not a directory
308     case EADDRINUSE:  // Address already in use
309     case EBADF:       // Invalid file descriptor
310 #ifdef EBADFD
311     case EBADFD:  // File descriptor in bad state
312 #endif
313     case EBUSY:    // Device or resource busy
314     case ECHILD:   // No child processes
315     case EISCONN:  // Socket is connected
316 #ifdef EISNAM
317     case EISNAM:  // Is a named type file
318 #endif
319 #ifdef ENOTBLK
320     case ENOTBLK:  // Block device required
321 #endif
322     case ENOTCONN:  // The socket is not connected
323     case EPIPE:     // Broken pipe
324 #ifdef ESHUTDOWN
325     case ESHUTDOWN:  // Cannot send after transport endpoint shutdown
326 #endif
327     case ETXTBSY:  // Text file busy
328 #ifdef EUNATCH
329     case EUNATCH:  // Protocol driver not attached
330 #endif
331       return StatusCode::kFailedPrecondition;
332     case ENOSPC:  // No space left on device
333 #ifdef EDQUOT
334     case EDQUOT:  // Disk quota exceeded
335 #endif
336     case EMFILE:   // Too many open files
337     case EMLINK:   // Too many links
338     case ENFILE:   // Too many open files in system
339     case ENOBUFS:  // No buffer space available
340     case ENODATA:  // No message is available on the STREAM read queue
341     case ENOMEM:   // Not enough space
342     case ENOSR:    // No STREAM resources
343 #ifdef EUSERS
344     case EUSERS:  // Too many users
345 #endif
346       return StatusCode::kResourceExhausted;
347 #ifdef ECHRNG
348     case ECHRNG:  // Channel number out of range
349 #endif
350     case EFBIG:      // File too large
351     case EOVERFLOW:  // Value too large to be stored in data type
352     case ERANGE:     // Result too large
353       return StatusCode::kOutOfRange;
354 #ifdef ENOPKG
355     case ENOPKG:  // Package not installed
356 #endif
357     case ENOSYS:        // Function not implemented
358     case ENOTSUP:       // Operation not supported
359     case EAFNOSUPPORT:  // Address family not supported
360 #ifdef EPFNOSUPPORT
361     case EPFNOSUPPORT:  // Protocol family not supported
362 #endif
363     case EPROTONOSUPPORT:  // Protocol not supported
364 #ifdef ESOCKTNOSUPPORT
365     case ESOCKTNOSUPPORT:  // Socket type not supported
366 #endif
367     case EXDEV:  // Improper link
368       return StatusCode::kUnimplemented;
369     case EAGAIN:  // Resource temporarily unavailable
370 #ifdef ECOMM
371     case ECOMM:  // Communication error on send
372 #endif
373     case ECONNREFUSED:  // Connection refused
374     case ECONNABORTED:  // Connection aborted
375     case ECONNRESET:    // Connection reset
376     case EINTR:         // Interrupted function call
377 #ifdef EHOSTDOWN
378     case EHOSTDOWN:  // Host is down
379 #endif
380     case EHOSTUNREACH:  // Host is unreachable
381     case ENETDOWN:      // Network is down
382     case ENETRESET:     // Connection aborted by network
383     case ENETUNREACH:   // Network unreachable
384     case ENOLCK:        // No locks available
385     case ENOLINK:       // Link has been severed
386 #ifdef ENONET
387     case ENONET:  // Machine is not on the network
388 #endif
389       return StatusCode::kUnavailable;
390     case EDEADLK:  // Resource deadlock avoided
391 #ifdef ESTALE
392     case ESTALE:  // Stale file handle
393 #endif
394       return StatusCode::kAborted;
395     case ECANCELED:  // Operation cancelled
396       return StatusCode::kCancelled;
397     default:
398       return StatusCode::kUnknown;
399   }
400 }
401 
402 namespace {
MessageForErrnoToStatus(int error_number,absl::string_view message)403 std::string MessageForErrnoToStatus(int error_number,
404                                     absl::string_view message) {
405   return absl::StrCat(message, ": ",
406                       absl::base_internal::StrError(error_number));
407 }
408 }  // namespace
409 
ErrnoToStatus(int error_number,absl::string_view message)410 Status ErrnoToStatus(int error_number, absl::string_view message) {
411   return Status(ErrnoToStatusCode(error_number),
412                 MessageForErrnoToStatus(error_number, message));
413 }
414 
StatusMessageAsCStr(const Status & status)415 const char* StatusMessageAsCStr(const Status& status) {
416   // As an internal implementation detail, we guarantee that if status.message()
417   // is non-empty, then the resulting string_view is null terminated.
418   auto sv_message = status.message();
419   return sv_message.empty() ? "" : sv_message.data();
420 }
421 
422 ABSL_NAMESPACE_END
423 }  // namespace absl
424