1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36 
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38 
39 #pragma once
40 
41 /* The problem with assert.h:  If NDEBUG is set then it doesn't execute the function, if NDEBUG isn't set then we get a branch that isn't taken. */
42 
43 /* This version will complain if NDEBUG is set. */
44 /* It evaluates the argument and then calls a function  toku_do_assert() which takes all the hits for the branches not taken. */
45 
46 #include <portability/toku_config.h>
47 
48 #include <stdint.h>
49 #include <errno.h>
50 #include <stdio.h>
51 
52 #ifdef NDEBUG
53 #error NDEBUG should not be set
54 #endif
55 
56 inline int get_error_errno(void);
57 
get_maybe_error_errno(void)58 static inline int get_maybe_error_errno(void) { return errno; }
59 
60 static inline void
set_errno(int new_errno)61 set_errno(int new_errno)
62 {
63     errno = new_errno;
64 }
65 
66 void toku_assert_init(void) __attribute__((constructor));
67 
68 void toku_assert_set_fpointers(int (*toku_maybe_get_engine_status_text_pointer)(char*, int),
69                                int (*toku_maybe_err_engine_status_pointer)(void),
70 			       void (*toku_maybe_set_env_panic_pointer)(int, const char*),
71                                uint64_t num_rows);
72 
73 void toku_do_assert(int /*expr*/,const char*/*expr_as_string*/,const char */*fun*/,const char*/*file*/,int/*line*/, int/*errno*/) __attribute__((__visibility__("default")));
74 
75 void toku_do_assert_fail(const char*/*expr_as_string*/,const char */*fun*/,const char*/*file*/,int/*line*/, int/*errno*/) __attribute__((__visibility__("default"))) __attribute__((__noreturn__));
76 void toku_do_assert_zero_fail(uintptr_t/*expr*/, const char*/*expr_as_string*/,const char */*fun*/,const char*/*file*/,int/*line*/, int/*errno*/) __attribute__((__visibility__("default"))) __attribute__((__noreturn__));
77 void toku_do_assert_expected_fail(uintptr_t/*expr*/, uintptr_t /*expected*/, const char*/*expr_as_string*/,const char */*fun*/,const char*/*file*/,int/*line*/, int/*errno*/) __attribute__((__visibility__("default"))) __attribute__((__noreturn__));
78 
79 // Define GCOV if you want to get test-coverage information that ignores the assert statements.
80 // #define GCOV
81 
82 extern void (*do_assert_hook)(void); // Set this to a function you want called after printing the assertion failure message but before calling abort().  By default this is NULL.
83 // copied here from ydb-internal.h to avoid inclusion hell, the void * is really a DB_ENV but we don't have that type here
84 typedef void (*toku_env_err_func)(const void * env, int error, const char *fmt, ...);
85 void db_env_do_backtrace_errfunc(toku_env_err_func errfunc, const void *env);
86 void db_env_do_backtrace(FILE *outf);
87 
88 #ifdef assert
89 #  undef assert
90 #endif
91 #if defined(GCOV)
92 #define assert(expr)      toku_do_assert((expr) != 0, #expr, __FUNCTION__, __FILE__, __LINE__, get_maybe_error_errno())
93 #define assert_zero(expr) toku_do_assert((expr) == 0, #expr, __FUNCTION__, __FILE__, __LINE__, get_maybe_error_errno())
94 #define assert_equals(expr, expected) toku_do_assert((expr) == (expected), (expected), #expr, __FUNCTION__, __FILE__, __LINE__, get_maybe_error_errno())
95 #else
96 #define assert(expr)      ((expr)      ? (void)0 : toku_do_assert_fail(#expr, __FUNCTION__, __FILE__, __LINE__, get_maybe_error_errno()))
97 #define assert_zero(expr) ((expr) == 0 ? (void)0 : toku_do_assert_zero_fail((uintptr_t)(expr), #expr, __FUNCTION__, __FILE__, __LINE__, get_maybe_error_errno()))
98 #define assert_equals(expr, expected) ((expr) == (expected) ? (void)0 : toku_do_assert_expected_fail((uintptr_t)(expr), (uintptr_t)(expected), #expr, __FUNCTION__, __FILE__, __LINE__, get_maybe_error_errno()))
99 #define assert_null(expr) ((expr) == nullptr ? (void)0 : toku_do_assert_zero_fail((uintptr_t)(expr), #expr, __FUNCTION__, __FILE__, __LINE__, get_maybe_error_errno()))
100 #endif
101 
102 #ifdef GCOV
103 #define WHEN_GCOV(x) x
104 #define WHEN_NOT_GCOV(x)
105 #else
106 #define WHEN_GCOV(x)
107 #define WHEN_NOT_GCOV(x) x
108 #endif
109 
110 #if !defined(__clang__)
111 #include <type_traits>
112 # define ENSURE_POD(type) static_assert(std::is_pod<type>::value, #type " isn't POD")
113 #else
114 # define ENSURE_POD(type) // TEMP, clang is much more strict about POD.
115 #endif
116 
117 #define lazy_assert(a)          assert(a)      // indicates code is incomplete
118 #define lazy_assert_zero(a)     assert_zero(a) // indicates code is incomplete
119 #define lazy_assert_equals(a, b)     assert_equals(a, b) // indicates code is incomplete
120 #define invariant(a)            assert(a)      // indicates a code invariant that must be true
121 #define invariant_null(a)       assert_null(a) // indicates a code invariant that must be true
122 #define invariant_notnull(a)    assert(a)      // indicates a code invariant that must be true
123 #define invariant_zero(a)       assert_zero(a) // indicates a code invariant that must be true
124 #define invariant_equals(a, b)       assert_equals(a, b) // indicates a code invariant that must be true
125 #define resource_assert(a)      assert(a)      // indicates resource must be available, otherwise unrecoverable
126 #define resource_assert_zero(a) assert_zero(a) // indicates resource must be available, otherwise unrecoverable
127 #define resource_assert_equals(a, b) assert_equals(a, b) // indicates resource must be available, otherwise unrecoverable
128 
129 #if defined(TOKU_DEBUG_PARANOID) && TOKU_DEBUG_PARANOID
130 #define paranoid_invariant(a) assert(a)
131 #define paranoid_invariant_null(a) assert_null(a)
132 #define paranoid_invariant_notnull(a) assert(a)
133 #define paranoid_invariant_zero(a) assert_zero(a)
134 #else // !TOKU_DEBUG_PARANOID
135 #define paranoid_invariant(a) ((void) 0)
136 #define paranoid_invariant_null(a) ((void) 0)
137 #define paranoid_invariant_notnull(a) ((void) 0)
138 #define paranoid_invariant_zero(a) ((void)0)
139 #endif
140 
get_error_errno(void)141 inline int get_error_errno(void) {
142     invariant(errno);
143     return errno;
144 }
145 
146 extern bool toku_gdb_dump_on_assert;
147