File: s2n_result.h

package info (click to toggle)
aws-crt-python 0.28.4%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 78,428 kB
  • sloc: ansic: 437,955; python: 27,657; makefile: 5,855; sh: 4,289; ruby: 208; java: 82; perl: 73; cpp: 25; xml: 11
file content (133 lines) | stat: -rw-r--r-- 4,139 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

#pragma once

/*
 * The goal of s2n_result is to provide a strongly-typed error
 * signal value, which provides the compiler with enough information
 * to catch bugs.
 *
 * Historically, s2n has used int to signal errors. This has caused a few issues:
 *
 * ## GUARD in a function returning integer types
 *
 * There is no compiler error if `GUARD(nested_call());` is used in a function
 * that is meant to return integer type - not a error signal.
 *
 * ```c
 * uint8_t s2n_answer_to_the_ultimate_question() {
 *   POSIX_GUARD(s2n_sleep_for_years(7500000));
 *   return 42;
 * }
 * ```
 *
 * In this function we intended to return a `uint8_t` but used a
 * `GUARD` which will return -1 if the call fails. This can lead to
 * very subtle bugs.
 *
 * ## `GUARD`ing a function returning any integer type
 *
 * There is no compiler error if `GUARD(nested_call());` is used
 * on a function that doesn't actually return an error signal
 *
 * ```c
 * int s2n_deep_thought() {
 *   POSIX_GUARD(s2n_answer_to_the_ultimate_question());
 *   return 0;
 * }
 * ```
 *
 * In this function we intended guard against a failure of
 * `s2n_answer_to_the_ultimate_question` but that function doesn't
 * actually return an error signal. Again, this can lead to sublte
 * bugs.
 *
 * ## Ignored error signals
 *
 * Without the `warn_unused_result` function attribute, the compiler
 * provides no warning when forgetting to `GUARD` a function. Missing
 * a `GUARD` can lead to subtle bugs.
 *
 * ```c
 * int s2n_answer_to_the_ultimate_question() {
 *   s2n_sleep_for_years(7500000); // <- THIS SHOULD BE GUARDED!!!
 *   return 42;
 * }
 * ```
 *
 * # Solution
 *
 * s2n_result provides a newtype declaration, which is popular in
 * languages like [Haskell](https://wiki.haskell.org/Newtype) and
 * [Rust](https://doc.rust-lang.org/rust-by-example/generics/new_types.html).
 *
 * Functions that return S2N_RESULT are automatically marked with the
 * `warn_unused_result` attribute, which ensures they are GUARDed.
 */

#include <stdbool.h>

#include "api/s2n.h"

/* A value which indicates the outcome of a function */
typedef struct {
    int __error_signal;
} s2n_result;

/* used to signal a successful function return */
#define S2N_RESULT_OK ((s2n_result){ S2N_SUCCESS })

/* used to signal an error while executing a function */
#define S2N_RESULT_ERROR ((s2n_result){ S2N_FAILURE })

#if defined(__clang__) || defined(__GNUC__)
    #define S2N_RESULT_MUST_USE __attribute__((warn_unused_result))
#else
    #define S2N_RESULT_MUST_USE
#endif

/* returns true when the result is S2N_RESULT_OK */
S2N_RESULT_MUST_USE static inline bool s2n_result_is_ok(s2n_result result)
{
    return result.__error_signal == S2N_SUCCESS;
}

/* returns true when the result is S2N_RESULT_ERROR */
S2N_RESULT_MUST_USE static inline bool s2n_result_is_error(s2n_result result)
{
    return result.__error_signal != S2N_SUCCESS;
}

/**
 * Ignores the returned result of a function
 *
 * Generally, function results should always be checked. Using this function
 * could cause the system to behave in unexpected ways. As such, this function
 * should only be used in scenarios where the system state is not affected by
 * errors.
 */
static inline void s2n_result_ignore(s2n_result result)
{
    /* noop */
}

/* used in function declarations to signal function fallibility */
#define S2N_RESULT S2N_RESULT_MUST_USE s2n_result

/* The DEFER_CLEANUP macro discards the result of its cleanup function.
 * We need a version of s2n_result which can be ignored.
 */
#define S2N_CLEANUP_RESULT s2n_result