feisty meow concerns codebase  2.140
callstack_tracker.cpp
Go to the documentation of this file.
1 
2 
3 
4 /*****************************************************************************\
5 * *
6 * Name : callstack_tracker *
7 * Author : Chris Koeritz *
8 * *
9 *******************************************************************************
10 * Copyright (c) 2007-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
17 
18 #ifdef ENABLE_CALLSTACK_TRACKING
19 
20 // note: this object cannot be constructed when the memory_checker is still
21 // tracking memory leaks. it must be disabled so that this object can
22 // construct without being tracked, which causes an infinite loop. the code
23 // in the basis extern support takes care of that for us.
24 
25 #include "callstack_tracker.h"
26 
27 #include <malloc.h>
28 #include <stdio.h>
29 
31 //is this right way to clean that out.
32 
33 const int MAX_STACK_DEPTH = 2000;
34  // beyond that many stack frames, we will simply refuse to add any more.
35 
36 const int MAX_TEXT_FIELD = 1024;
37  // the most space we allow the class, function, and file to take up.
38 
39 const char *emptiness_note = "Empty Stack\n";
41 
43 
44 class callstack_records
45 {
46 public:
47  frame_tracking_instance _records[MAX_STACK_DEPTH + 2]; // fudging room.
48 };
49 
51 
52 // our current depth gives us our position in the array. we define our
53 // stack as starting at element zero, which is a null stack entry and
54 // corresponds to a depth of zero also. then, when the stack depth is one,
55 // we actually have an element in place and it resides at index 1. this
56 // scheme allows us to have an update to the line number just do nothing when
57 // there is no current stack.
58 
59 callstack_tracker::callstack_tracker()
60 : _bt(new callstack_records),
61  _depth(0),
62  _frames_in(0),
63  _frames_out(0),
64  _highest(0),
65  _unusable(false)
66 {
67 //printf("callstack ctor\n");
68 }
69 
70 callstack_tracker::~callstack_tracker()
71 {
72 //printf("!!!!!!!!!!!!!!!!!! callstack dtor in\n");
73  _unusable = true;
74  WHACK(_bt);
75 //printf("!!!!!!!!!!!!!!!!!! callstack dtor out\n");
76 }
77 
78 bool callstack_tracker::push_frame(const char *class_name, const char *func,
79  const char *file, int line)
80 {
81 //printf("callstack pushframe depth=%d in\n", _depth);
82  if (_unusable) return false;
83  if (_depth >= MAX_STACK_DEPTH) {
84  // too many frames already.
85  printf("callstack_tracker::push_frame: past limit at class=%s func=%s "
86  "file=%s line=%d\n", class_name, func, file, line);
87  return false;
88  }
89  _depth++;
90  if (_depth > _highest) _highest = _depth;
91  _frames_in += 1;
92  _bt->_records[_depth].assign(class_name, func, file, line);
93 //printf("callstack pushframe depth=%d out\n", _depth);
94  return true;
95 }
96 
97 bool callstack_tracker::pop_frame()
98 {
99 //printf("callstack popframe depth=%d in\n", _depth);
100  if (_unusable) return false;
101  if (_depth <= 0) {
102  // how inappropriate of them; we have no frames.
103  _depth = 0; // we don't lose anything useful by forcing it to be zero.
104  printf("callstack_tracker::pop_frame stack underflow!\n");
105  return false;
106  }
107  _bt->_records[_depth].clean();
108  _depth--;
109  _frames_out += 1;
110 //printf("callstack popframe depth=%d out\n", _depth);
111  return true;
112 }
113 
114 bool callstack_tracker::update_line(int line)
115 {
116  if (_unusable) return false;
117  if (!_depth) return false; // not as serious, but pretty weird.
118  _bt->_records[_depth]._line = line;
119  return true;
120 }
121 
122 char *callstack_tracker::full_trace() const
123 {
124  if (_unusable) return strdup("");
125 //printf("fulltrace in\n");
126  char *to_return = (char *)malloc(full_trace_size());
127  to_return[0] = '\0';
128  if (!_depth) {
129  strcat(to_return, emptiness_note);
130  return to_return;
131  }
132  const int initial_len = MAX_TEXT_FIELD + 8;
133  char temp[initial_len];
134  int allowed_len = initial_len;
135  // space provided for one text line.
136  // start at top most active frame and go down towards bottom most.
137  for (int i = _depth; i >= 1; i--) {
138  strcat(to_return, "\t"); // we left space for this and \n at end.
139  temp[0] = '\0';
140  int len_class = strlen(_bt->_records[i]._class);
141  int len_func = strlen(_bt->_records[i]._func);
142  if (allowed_len > len_class + len_func + 6) {
143  allowed_len -= len_class + len_func + 6;
144  sprintf(temp, "\"%s::%s\", ", _bt->_records[i]._class,
145  _bt->_records[i]._func);
146  strcat(to_return, temp);
147  }
148 
149  temp[0] = '\0';
150  int len_file = strlen(_bt->_records[i]._file);
151  if (allowed_len > len_file + 4) {
152  allowed_len -= len_file + 4;
153  sprintf(temp, "\"%s\", ", _bt->_records[i]._file);
154  strcat(to_return, temp);
155  }
156 
157  temp[0] = '\0';
158  sprintf(temp, "\"line=%d\"", _bt->_records[i]._line);
159  int len_line = strlen(temp);
160  if (allowed_len > len_line) {
161  allowed_len -= len_line;
162  strcat(to_return, temp);
163  }
164 
165  strcat(to_return, "\n"); // we left space for this already.
166  }
167 
168 //printf("fulltrace out\n");
169  return to_return;
170 }
171 
172 int callstack_tracker::full_trace_size() const
173 {
174  if (_unusable) return 0;
175  if (!_depth) return strlen(emptiness_note) + 14; // liberal allocation.
176  int to_return = 28; // another hollywood style excess.
177  for (int i = _depth; i >= 1; i--) {
178  int this_line = 0; // add up parts for just this item.
179 
180  // all of these additions are completely dependent on how it's done above.
181 
182  int len_class = strlen(_bt->_records[i]._class);
183  int len_func = strlen(_bt->_records[i]._func);
184  this_line += len_class + len_func + 6;
185 
186  int len_file = strlen(_bt->_records[i]._file);
187  this_line += len_file + 4;
188 
189  this_line += 32; // extra space for line number and such.
190 
191  // limit it like we did above; we will use the lesser size value.
192  if (this_line < MAX_TEXT_FIELD + 8) to_return += this_line;
193  else to_return += MAX_TEXT_FIELD + 8;
194  }
195  return to_return;
196 }
197 
199 
201  const char *func, const char *file, int line, bool add_frame)
202 : _frame_involved(add_frame),
203  _class(class_name? strdup(class_name) : NULL_POINTER),
204  _func(func? strdup(func) : NULL_POINTER),
205  _file(file? strdup(file) : NULL_POINTER),
206  _line(line)
207 {
208  if (_frame_involved) {
209 //printf("frametrackinst ctor in class=%s func=%s\n", class_name, func);
210  program_wide_stack_trace().push_frame(class_name, func, file, line);
211 //printf("frametrackinst ctor out\n");
212  }
213 }
214 
216  (const frame_tracking_instance &to_copy)
217 : _frame_involved(false), // copies don't get a right to this.
218  _class(to_copy._class? strdup(to_copy._class) : NULL_POINTER),
219  _func(to_copy._func? strdup(to_copy._func) : NULL_POINTER),
220  _file(to_copy._file? strdup(to_copy._file) : NULL_POINTER),
221  _line(to_copy._line)
222 {
223 }
224 
225 frame_tracking_instance::~frame_tracking_instance() { clean(); }
226 
227 void frame_tracking_instance::clean()
228 {
229  if (_frame_involved) {
230 //printf("frametrackinst clean\n");
231  program_wide_stack_trace().pop_frame();
232  }
233  _frame_involved = false;
234  free(_class); _class = NULL_POINTER;
235  free(_func); _func = NULL_POINTER;
236  free(_file); _file = NULL_POINTER;
237  _line = 0;
238 }
239 
240 frame_tracking_instance &frame_tracking_instance::operator =
241  (const frame_tracking_instance &to_copy)
242 {
243 //printf("frametrackinst tor = in\n");
244  if (this == &to_copy) return *this;
245  assign(to_copy._class, to_copy._func, to_copy._file, to_copy._line);
246 //printf("frametrackinst tor = out\n");
247  return *this;
248 }
249 
250 void frame_tracking_instance::assign(const char *class_name, const char *func,
251  const char *file, int line)
252 {
253  clean();
254  _frame_involved = false; // copies don't get a right to this.
255  _class = class_name? strdup(class_name) : NULL_POINTER;
256  _func = func? strdup(func) : NULL_POINTER;
257  _file = file? strdup(file) : NULL_POINTER;
258  _line = line;
259 }
260 
262 {
263 //printf("frametrackinst updatelinenum in\n");
264  program_wide_stack_trace().update_line(line);
265 //printf("frametrackinst updatelinenum out\n");
266 }
267 
268 #endif // ENABLE_CALLSTACK_TRACKING
269 
270 
271 
272 
#define update_current_stack_frame_line_number(line)
#define frame_tracking_instance
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121