acme
Foundational cross-platform layer of the ca2 framework
Loading...
Searching...
No Matches
debug.h
1#pragma once
2
3
4
5/*
6Why does ASSUME exist?
7
8acme 8 has two existing validation models
9
10ASSERT/VERIFY - These are used to make sure a debug build reports a problem with the expression/invariant
11ENSURE - Debug is the same as VERIFY, retail throws a C++ exception
12
13We added ENSURE because there were too many unreported error paths in acme and we wanted to bail out of more
14error conditions rather than just trying to continue in retail.
15
16There might be a case for changing 'lots' of ASSERT to ENSURE, but we chose an incremental approach and only
17changed over where we saw a problem with code reported from a customer or test case. This reduces code churn in our
18code for this version.
19
20In general, our approach is to try to make sure that when something goes wrong
21- the client does not continue to run, because we report an error condition
22- debug builds see an assertion about the problem
23
24Sometimes we have code like
25
26HRESULT ComMethod()
27{
28 ASSUME(m_pFoo);
29 return m_pFoo->Method();
30}
31
32We could add
33 if(!m_pFoo) return E_POINTER;
34
35But this is very unlikely to help, since it erases the ability of the developer to debug this problem if it's seen in a retail
36build of the application.
37
38We could try something more severe
39
40 if(!m_pFoo) terminate(); // or your favourite shutdown function
41
42This would ensure good reporting (because VC8 terminate generates a Windows Error Report and crash dump), but hardly seems a big win
43over the previous crash.
44
45ENSURE might seem slightly better. It is debuggable and consistent with acme in general. In fact, many parts of acme do just this.
46But in this specific action_context, it doesn't look like a great choice. COM methods should not in general be emitting native C++ exceptions
47as an error reporting strategy.
48
49So we find ourselves in a quandry. For these kinds of methods, the traditional code (ASSERT followed by a crash), seems be the most
50debuggable thing to do in this situation. At least for VS8, we have decided to stick with this shape.
51
52---
53
54Now consider the impact of cl /analyze. We want cl /analyze to not warn about our potential dereferences when they refer to member variables
55whose state was previously validated by another method. But we do want to see the impact of function contracts on the parameters of the
56function.
57
58So we've done a broad replace of all the member-related ASSERT to ASSUME.
59
60*/
61
62#ifndef __analysis_assume // [
63#ifdef _PREFAST_ // [
64#define __analysis_assume(expr) __assume(expr)
65#else // ][
66#define __analysis_assume(expr)
67#endif // ]
68#endif // ]
69
70#ifndef ASSUME
71#if defined(VC6) || defined(VC71)
72#define ASSUME(expr) (expr);
73#else
74#define ASSUME(expr) do { ASSERT(expr); __analysis_assume(!!(expr)); } while(0)
75#endif
76#endif // ASSERT
77
78#ifndef VERIFY
79#ifdef _DEBUG
80#define VERIFY(expr) ASSERT(expr)
81#else
82#define VERIFY(expr) (expr ? void() : throw ::exception());
83#endif // __DEBUG
84#endif // VERIFY
85
86
87#ifndef ENSURE_SUCCEEDED
88#define ENSURE_SUCCEEDED(hr) ENSURE_THROW(SUCCEEDED(hr), hr)
89#endif // ENSURE
90
91/* Used inside COM methods that do not want to throw ::exception( */
92#ifndef ENSURE_RETURN_HR
93#define ENSURE_RETURN_HR(expr, hr) \
94do { \
95 ::i32 __atl_condVal=!!(expr); \
96 ASSERT(__atl_condVal); \
97 if(!(__atl_condVal)) return hr; \
98} while (0)
99#endif
100
101
102/* Used inside COM methods that do not want to throw ::exception( */
103#ifndef ENSURE_RETURN
104#define ENSURE_RETURN(expr) ENSURE_RETURN_HR(expr, E_FAIL)
105#endif
106
107
108
109
110//#include "acme/networking/sockets/trace_interface.h"
111
112
113CLASS_DECL_ACME void __trace(enum_trace_level elevel, const ::scoped_string & scopedstrTag, const ::scoped_string & scopedstr, const ::scoped_string & scopedstrFile = nullptr, ::i32 iLine = -1);
114
115
116#define _DEBUG_WIDE_(s) L ## s
117#define _DEBUG_WIDE(s) _DEBUG_WIDE_(s)
118
119#define _NORMAL_BLOCK 1
120
121
122CLASS_DECL_ACME ::i32 DECL_C debug_report(
123::i32 _ReportType,
124const_char_pointer _Filename,
125::i32 _LineNumber,
126const_char_pointer _ModuleName,
127const_char_pointer _Format,
128...);
129
130
131CLASS_DECL_ACME ::i32 DECL_C debug_report(
132::i32 _ReportType,
133const wchar_t * _Filename,
134::i32 _LineNumber,
135const wchar_t * _ModuleName,
136const wchar_t * _Format,
137...);
138
139
141//
142// Debug Reporting
143//
144typedef void * _HFILE; /* file handle pointer */
145
146#define _DEBUG_WARN 0
147#define _DEBUG_ERROR 1
148#define _DEBUG_ASSERT 2
149#define _DEBUG_ERRCNT 3
150
151#define _DEBUG_MODE_FILE 0x1
152#define _DEBUG_MODE_DEBUG 0x2
153#define _DEBUG_MODE_WNDW 0x4
154#define _DEBUG_REPORT_MODE -1
155
156#ifndef WINDOWS
157
158#if defined(_M_IX86)
159#define _DEBUG_INVALID_HFILE ((_HFILE)-1)
160#define _DEBUG_HFILE_ERROR ((_HFILE)-2)
161#define _DEBUG_FILE_STDOUT ((_HFILE)-4)
162#define _DEBUG_FILE_STDERR ((_HFILE)-5)
163#define _DEBUG_REPORT_FILE ((_HFILE)-6)
164#else
165#define _DEBUG_INVALID_HFILE ((_HFILE)(::i64)-1)
166#define _DEBUG_HFILE_ERROR ((_HFILE)(::i64)-2)
167#define _DEBUG_FILE_STDOUT ((_HFILE)(::i64)-4)
168#define _DEBUG_FILE_STDERR ((_HFILE)(::i64)-5)
169#define _DEBUG_REPORT_FILE ((_HFILE)(::i64)-6)
170#endif
171
172#endif
173
174
175#define _DEBUG_RPTHOOK_INSTALL 0
176#define _DEBUG_RPTHOOK_REMOVE 1
177
178
179#define _DEBUG_ALLOC_MEM_DF 0x01 /* Turn on debug allocation */
180#define _DEBUG_DELAY_FREE_MEM_DF 0x02 /* Don't actually free memory */
181#define _DEBUG_CHECK_ALWAYS_DF 0x04 /* Check heap every alloc/dealloc */
182#define _DEBUG_RESERVED_DF 0x08 /* Reserved - do not use */
183#define _DEBUG_CHECK_DEBUG_DF 0x10 /* Leak check/diff __DEBUG blocks */
184#define _DEBUG_LEAK_CHECK_DF 0x20 /* Leak check at program exit */
185
186/*
187 * Some bit values for _crtDbgFlag which correspond to frequencies for checking
188 * the the heap.
189 */
190#define _DEBUG_CHECK_EVERY_16_DF 0x00100000 /* check heap every 16 heap ops */
191#define _DEBUG_CHECK_EVERY_128_DF 0x00800000 /* check heap every 128 heap ops */
192#define _DEBUG_CHECK_EVERY_1024_DF 0x04000000 /* check heap every 1024 heap ops */
193/*
194We do not check the heap by default at this i32_point because the cost was too high
195for some applications. You can still turn this feature on manually.
196 */
197#define _DEBUG_CHECK_DEFAULT_DF 0
198
199#define _DEBUG_REPORT_FLAG -1 /* Query bitflag status */
200
201#define _BLOCK_TYPE(block) (block & 0xFFFF)
202#define _BLOCK_SUBTYPE(block) (block >> 16 & 0xFFFF)
203
204
205/****************************************************************************
206 *
207 * Memory state
208 *
209 ***************************************************************************/
210
211/* Memory block identification */
212#define _FREE_BLOCK 0
213#define _NORMAL_BLOCK 1
214#define _DEBUG_BLOCK 2
215#define _IGNORE_BLOCK 3
216#define _CLIENT_BLOCK 4
217#define _MAX_BLOCKS 5
218
219
220
221struct MEMORY_BLOCK_HEADER;
222
223typedef struct _MEMORY_STATE
224{
225
226 struct MEMORY_BLOCK_HEADER * pBlockHeader;
227 size_t lCounts[_MAX_BLOCKS];
228 size_t lSizes[_MAX_BLOCKS];
229 size_t lHighWaterCount;
230 size_t lTotalCount;
231
232} MEMORY_STATE;
233
234
235/****************************************************************************
236 *
237 * Declarations, prototype and function-like macros
238 *
239 ***************************************************************************/
240
241/* _STATIC_ASSERT is for enforcing boolean/integral conditions at compile time.
242 Since it is purely a compile-time mechanism that generates no code, the check
243 is left in even if __DEBUG is not defined. */
244
245#ifndef _STATIC_ASSERT
246#define _STATIC_ASSERT(expr) typedef ::i8 __static_assert_t[ (expr) ]
247#endif
248
249#ifndef _DEBUG
250
252//
253// Debug OFF
254
255
257//
258// We allow our basic _ASSERT macros to be overridden by pre-existing definitions.
259// This is not the ideal mechanism, but is helpful in some scenarios and helps avoid
260// multiple definition problems
261
262#ifndef _ASSERT
263#define _ASSERT(expr) ((void)0)
264#endif
265
266#ifndef _ASSERTE
267#define _ASSERTE(expr) ((void)0)
268#endif
269
270#ifndef _ASSERT_EXPR
271#define _ASSERT_EXPR(expr, expr_str) (()0)
272#endif
273
274//
275// __DEBUG Off
276//
278
279
280#elif !defined(__MDEBUG) && !defined(__VLD)
281
282
284//
285// __DEBUG ON
286//
287
288
290//
291// Asserts
292// We use !! below to ensure that any overloaded operators used to evaluate expr do not end up at operator ||
293//
294#undef _ASSERT_EXPR
295#define _ASSERT_EXPR(expr, msg) \
296 (void) ((!!(expr)) || \
297 (1 != debug_report(_DEBUG_ASSERT, _DEBUG_WIDE(__FILE__), __LINE__, nullptr, msg)) || \
298 (debug_break(), 0))
299
300
301#ifndef _ASSERT
302#define _ASSERT(expr) _ASSERT_EXPR((expr), nullptr)
303#endif
304
305#ifndef _ASSERTE
306#define _ASSERTE(expr) _ASSERT_EXPR((expr), _T("##expr##"))
307#endif
308
309
310
311
312#endif
313
314
315
316// CLASS_DECL_ACME ::i32 FUNCTION_DEBUGBOX(const ::scoped_string & scopedstrMessage, const ::scoped_string & scopedstrTitle, ::i32 iFlags);
317
318// CLASS_DECL_ACME ::i32 FUNCTION_DEBUGBOXW(const WCHAR * pszMessage, const WCHAR * pszTitle, ::i32 iFlags);
319
320// inline ::i32 FUNCTION_XXDEBUGBOX(const ::scoped_string & scopedstrMessage, const ::scoped_string & scopedstrTitle, ::i32 iFlags)
321// {
322
323// __UNREFERENCED_PARAMETER(scopedstrMessage);
324// __UNREFERENCED_PARAMETER(scopedstrTitle);
325// __UNREFERENCED_PARAMETER(iFlags);
326
327// return 0;
328
329// }
330
331// inline ::i32 FUNCTION_XXDEBUGBOXW(const WCHAR * pszMessage, const WCHAR * pszTitle, ::i32 iFlags)
332// {
333
334// __UNREFERENCED_PARAMETER(scopedstrMessage);
335// __UNREFERENCED_PARAMETER(scopedstrTitle);
336// __UNREFERENCED_PARAMETER(iFlags);
337
338// return 0;
339
340// }
341
342//#define debug_box FUNCTION_DEBUGBOX
343//#define xxdebug_box FUNCTION_XXDEBUGBOX
344
345// Use!!
346// #include "acme/inline/set_xxdebug_box.inl"
347// and
348// #include "acme/inline/clear_xxdebug_box.inl"
349
350
351
352
353//void CLASS_DECL_ACME TRACELASTERROR();//
354
355
356
357//CLASS_DECL_ACME string FormatMessageFromSystem(::u32 dwError);
358
359
360
361
362
363
364//class CLASS_DECL_ACME trace_interface //:
366//{
367//public:
368//
369//
370//
371// //virtual void sockets_trace(::sockets::base_socket_handler * phandler, ::sockets::base_socket * psocket, enum_trace_level elevel, const ::scoped_string & scopedstrContext, ::i32 iError, const ::scoped_string & scopedstrContext) override;
372// //virtual void sockets_trace(::sockets::base_socket_handler * phandler, ::sockets::base_socket * psocket, enum_trace_level elevel, const ::scoped_string & scopedstrContext, ::i32 iError, const ::scoped_string & scopedstrContext) override;
373//
374//
375//};
376
377
378//extern critical_section * g_pcsTrace;
379//extern matter * g_pobjecTracer;
380//
381CLASS_DECL_ACME void os_trace(enum_trace_level elevel, const ::scoped_string & scopedstrTag, const ::scoped_string & scopedstrMessage);
382//CLASS_DECL_ACME void trace(enum_trace_level elevel, const ::scoped_string & scopedstrTag, const ::scoped_string & scopedstr, const ::scoped_string & scopedstrFile = nullptr, ::i32 iLine = -1);
383
384
385
386
387
388
389
390//#define LOG(level, tag) ::text_stream_log_line(level, tag, __FILE__, __LINE__)
391
392
393
394//#define cinfo LOG(e_trace_level_information, LOG_TAG)
395//#define cwarn LOG(e_trace_level_warning, LOG_TAG)
396//#define cerror LOG(e_trace_level_error, LOG_TAG)
397//#define cfatal LOG(e_trace_level_fatal, LOG_TAG)
398
399
400//#define thisinfo LOG(e_trace_level_information, LOG_THIS_TAG) << LOG_MEMBER_PREFIX << "; "
401//#define thiswarn LOG(e_trace_level_warning, LOG_THIS_TAG) << LOG_MEMBER_PREFIX << "; "
402//#define thiserr LOG(e_trace_level_error, LOG_THIS_TAG) << LOG_MEMBER_PREFIX << "; "
403//#define thisfatal LOG(e_trace_level_fatal, LOG_THIS_TAG) << LOG_MEMBER_PREFIX << "; "
404
405//#define thisstart thisinfo << "start "
406//#define thisexit thisinfo << "exit " << str_flag_ifnumberparenthesizeandspace
407//#define thisok thisinfo << "ok " << str_flag_ifnumberparenthesizeandspace
408//#define thisexc thiserr << "exception " << str_flag_ifnumberparenthesizeandspace
409//#define thisexcall thiserr << "exception(...) " << str_flag_ifnumberparenthesizeandspace
410//#define thisfail thiserr << "failure " << str_flag_ifnumberparenthesizeandspace
411//#define thisend thisinfo << "end "
412
413
414
415//extern CLASS_DECL_ACME ::pointer< ::mutex > g_pmutexMemoryCounters;
416
417//CLASS_DECL_ACME bool memory_counter_on();
418
419//CLASS_DECL_ACME ::file::path memory_counter_base_path();
420
421
422
423//namespace acme
424//{
425// template < typename T >
426// T constraint(T t, T tMin, T tMax)
427// {
428//
429// return (t < tMin) ? tMin : ((t > tMax) ? tMax : t);
430//
431// }
432//
433//}
434//
435//
436//inline enum_trace_level trace_level_constraint(enum_trace_level elevel)
437//{
438//
439// return ::acme::constraint(elevel, e_trace_level_none, e_trace_level_count);
440//
441//}
442
443//
444//extern const_char_pointer g_pszTraceLevelName[];
445//
446//
447
448CLASS_DECL_ACME enum_trace_level trace_level_constraint(enum_trace_level elevel);
449//{
450//
451// return g_pszTraceLevelName[trace_level_constraint(elevel)];
452//
454
455CLASS_DECL_ACME const_char_pointer trace_level_name(enum_trace_level elevel);
456
457
458//extern ::i8 g_chaTraceLevel[];;;
459//
460//
461CLASS_DECL_ACME ::i8 trace_level_char(enum_trace_level elevel);
462//{
463//
464// return g_chaTraceLevel[trace_level_constraint(elevel)];
465//
466//}
467
468
469
470//CLASS_DECL_ACME bool is_verbose();
471
472
473
474
475
Definition debug.h:224