1 // -*- mode: C++ -*-
2 //
3 // Copyright (c) 2007, 2008, 2009, 2010, 2011, 2015, 2017 The University of Utah
4 // All rights reserved.
5 //
6 // This file is part of `csmith', a random generator of C programs.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are met:
10 //
11 // * Redistributions of source code must retain the above copyright notice,
12 // this list of conditions and the following disclaimer.
13 //
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29
30 #if HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include "DFSRndNumGenerator.h"
35
36 #include <cassert>
37 #include <iostream>
38 #include <sstream>
39
40 #include "CGOptions.h"
41 #include "Filter.h"
42 #include "SequenceFactory.h"
43 #include "Sequence.h"
44 #include "Error.h"
45 #include "SequenceLineParser.h"
46
47 // Represents the data for each random choice
48 class DFSRndNumGenerator::SearchState
49 {
50 public:
51 explicit SearchState(int index);
52 SearchState(const SearchState &s);
53 ~SearchState();
54
55 void initSearchState(bool init, int value, int bound);
56 void dump(const string &where);
57
58 // getters and setters
init()59 bool init() { return init_; }
set_init(bool init)60 void set_init(bool init) { init_ = init; }
61
value()62 int value() { return value_; }
set_value(int value)63 void set_value(int value) { value_ = value; }
inc_value(void)64 void inc_value(void) { ++value_; }
65
bound()66 int bound() { return bound_; }
set_bound(int bound)67 void set_bound(int bound) { bound_ = bound; }
68
index()69 int index() { return index_; }
70
71 private:
72 // Whether this state has been initialized
73 bool init_;
74 // Current value from 0...(bound - 1)
75 int value_;
76
77 int bound_;
78
79 int index_;
80 };
81
82 /*
83 *
84 */
SearchState(int index)85 DFSRndNumGenerator::SearchState::SearchState(int index)
86 : init_(false),
87 value_(0),
88 bound_(0),
89 index_(index)
90 {
91 // Nothing to do
92 }
93
SearchState(const DFSRndNumGenerator::SearchState & state)94 DFSRndNumGenerator::SearchState::SearchState(const DFSRndNumGenerator::SearchState &state)
95 : init_(state.init_),
96 value_(state.value_),
97 bound_(state.bound_),
98 index_(state.index_)
99 {
100
101 }
102 /*
103 *
104 */
~SearchState()105 DFSRndNumGenerator::SearchState::~SearchState()
106 {
107 // Nothing to do
108 }
109
110 /*
111 *
112 */
113 void
initSearchState(bool init,int value,int bound)114 DFSRndNumGenerator::SearchState::initSearchState(bool init, int value, int bound)
115 {
116 init_ = init;
117 value_ = value;
118 bound_ = bound;
119 }
120
121 #define DEBUG
122 #ifdef DEBUG
dump(const string & where)123 void DFSRndNumGenerator::SearchState::dump(const string &where)
124 {
125 cout << "[state]" << where << ", index = " << index_ << ", init = " << init_ << ", value = " << value_ << ", bound = " \
126 << bound_ << std::endl;
127 }
128 #else
dump(const string &)129 void DFSRndNumGenerator::SearchState::dump(const string &)
130 {
131 }
132 #endif
133 // ----------------------------------------------------------------------------------------------
134
135 DFSRndNumGenerator *DFSRndNumGenerator::impl_ = 0;
136
DFSRndNumGenerator(Sequence * concrete_seq)137 DFSRndNumGenerator::DFSRndNumGenerator(Sequence *concrete_seq)
138 : trace_string_(""),
139 decision_depth_(-1),
140 current_pos_(-1),
141 all_done_(false),
142 seq_(concrete_seq),
143 use_debug_sequence_(false)
144 {
145 init_states(CGOptions::max_exhaustive_depth());
146 }
147
~DFSRndNumGenerator()148 DFSRndNumGenerator::~DFSRndNumGenerator()
149 {
150 std::vector<DFSRndNumGenerator::SearchState *>::iterator i;
151 for (i = states_.begin(); i != states_.end(); ++i) {
152 delete (*i);
153 }
154 states_.clear();
155 SequenceFactory::destroy_sequences();
156 }
157
158 /*
159 * Singleton
160 */
161 DFSRndNumGenerator*
make_rndnum_generator()162 DFSRndNumGenerator::make_rndnum_generator()
163 {
164 if (impl_)
165 return impl_;
166
167 Sequence *seq = SequenceFactory::make_sequence();
168
169 impl_ = new DFSRndNumGenerator(seq);
170
171 assert(impl_);
172
173 std::string debug_sequence = CGOptions::dfs_debug_sequence();
174 if (!debug_sequence.empty()) {
175 std::vector<int> nums;
176 if (!SequenceLineParser<vector<int> >::parse_sequence(nums, debug_sequence, SequenceFactory::current_sep_char())) {
177 assert("dfs debugging sequence error!" && 0);
178 }
179 impl_->initialize_sequence(nums);
180 impl_->use_debug_sequence_ = true;
181 }
182
183 return impl_;
184 }
185
186 void
initialize_sequence(const vector<int> & v)187 DFSRndNumGenerator::initialize_sequence(const vector<int> &v)
188 {
189 size_t i = 0;
190 for (i = 0; i < v.size(); i++) {
191 seq_->add_number(v[i], 0, i);
192 }
193 }
194
195 #ifdef DEBUG
196 void
dumpCurrentState(int bound,const string & where)197 DFSRndNumGenerator::dumpCurrentState(int bound, const string &where)
198 {
199 cout << "[current]" << where << ", current_pos = " << current_pos_ \
200 << ", decision_depth = " << decision_depth_ << " , bound = " \
201 << bound << ", all_done = " << all_done_ << std::endl;
202 }
203 #else
204 void
dumpCurrentState(int,const string &)205 DFSRndNumGenerator::dumpCurrentState(int, const string &)
206 {
207 }
208 #endif
209
210 /*
211 * invoked from DepthSpec.cpp.
212 * returning true means that we do eager backtracking.
213 */
214 bool
eager_backtracking(int depth_needed)215 DFSRndNumGenerator::eager_backtracking(int depth_needed)
216 {
217 if (current_pos_ <= 0) {
218 // all_done_ = true;
219 // Error::set_error(BACKTRACKING_ERROR);
220 // return true;
221 return false;
222 }
223
224 int max_depth = CGOptions::max_exhaustive_depth();
225 int remain_depth = max_depth - current_pos_;
226 if (remain_depth >= depth_needed)
227 return false;
228
229 if (current_pos_ > decision_depth_) {
230 Error::set_error(BACKTRACKING_ERROR);
231 return true;
232 }
233
234 // reset decision depth
235 decision_depth_ = current_pos_;
236 for (int i = current_pos_ + 1; i < max_depth; ++i)
237 states_[i]->set_init(false);
238
239 Error::set_error(BACKTRACKING_ERROR);
240 return true;
241 }
242
243 int
revisit_node(DFSRndNumGenerator::SearchState * state,int local_current_pos,int bound,const Filter * filter,const string *)244 DFSRndNumGenerator::revisit_node(DFSRndNumGenerator::SearchState *state, int local_current_pos,
245 int bound, const Filter *filter, const string *)
246 {
247 int rv = state->value();
248 if (filter) {
249 if (rv >= bound) {
250 state->dump("");
251 dumpCurrentState(bound, "");
252 cout << "rv = " << rv << ", bound = " << bound << std::endl;
253 assert(0);
254 }
255
256 filter->filter(rv);
257
258 ERROR_GUARD(-1);
259
260 assert(current_pos_ < CGOptions::max_exhaustive_depth());
261
262 }
263 seq_->add_number(rv, bound, local_current_pos);
264 return rv;
265 }
266
267 bool
filter_invalid_nums(vector<int> * invalid_nums,int v)268 DFSRndNumGenerator::filter_invalid_nums(vector<int> *invalid_nums, int v)
269 {
270 if (!invalid_nums)
271 return false;
272
273 vector<int>::iterator i = find(invalid_nums->begin(), invalid_nums->end(), v);
274 return (i != invalid_nums->end());
275 }
276
277 int
random_choice(int bound,const Filter * filter,const string * where,vector<int> * invalid_nums)278 DFSRndNumGenerator::random_choice (int bound, const Filter *filter, const string *where, vector<int> *invalid_nums)
279 {
280 int err = Error::get_error();
281
282 if (err == BACKTRACKING_ERROR) {
283 return -1;
284 }
285 else if (err != SUCCESS) {
286 assert("request random number in an error state. " && 0);
287 }
288
289 ++current_pos_;
290 if (use_debug_sequence_) {
291 int rv = seq_->get_number_by_pos(current_pos_);
292 if (filter)
293 filter->filter(rv);
294 //cout << "current_pos _ = " << current_pos_ << ", length = " << seq_->sequence_length() << std::endl;
295 if (static_cast<unsigned int>(current_pos_) >= seq_->sequence_length() - 1) {
296 all_done_ = true;
297 }
298 return rv;
299 }
300
301 int local_current_pos = current_pos_;
302
303 if (current_pos_ >= CGOptions::max_exhaustive_depth() ||
304 decision_depth_ >= CGOptions::max_exhaustive_depth()) {
305 Error::set_error(EXCEED_MAX_DEPTH_ERROR);
306 return -1;
307 }
308
309 DFSRndNumGenerator::SearchState *state = states_[current_pos_];
310
311 state->set_bound(bound);
312 //dumpCurrentState(bound, "");
313 //state->dump("");
314
315 // Revisit a node
316 if (current_pos_ < decision_depth_ && state->init()) {
317 return revisit_node(state, local_current_pos, bound, filter, where);
318 }
319
320 if (state->init()) {
321 int v = state->value();
322 int local_decision_depth = decision_depth_;
323 do { // Filter out invalid value
324 ++v;
325 state->set_value(v);
326 current_pos_ = local_current_pos;
327 decision_depth_ = local_decision_depth;
328 ERROR_GUARD(-1);
329 } while (v < bound && ((filter && filter->filter(v)) || filter_invalid_nums(invalid_nums, v)));
330
331 state->set_value(v);
332
333 if (state->value() >= bound) { // backtracking
334 current_pos_ = local_current_pos;
335 for (int i = current_pos_; i < CGOptions::max_exhaustive_depth(); ++i) {
336 states_[i]->set_init(false);
337 }
338 --decision_depth_;
339 if (decision_depth_ < 0)
340 all_done_ = true;
341 Error::set_error(BACKTRACKING_ERROR);
342 return -1;
343 }
344 else { // switch branch
345 ERROR_GUARD(-1);
346
347 int rv = state->value();
348 seq_->add_number(rv, bound, local_current_pos);
349 return rv;
350 }
351 }
352 else { // First time to visit this node
353 int v = 0;
354
355 ++decision_depth_;
356 state->initSearchState(true, v, bound);
357
358 while (v < bound && ((filter && (filter->filter(v))) || filter_invalid_nums(invalid_nums, v))) { // Filter out invalid value
359 for (int i = decision_depth_; i < CGOptions::max_exhaustive_depth(); ++i) {
360 states_[i]->set_value(0);
361 }
362 ERROR_GUARD(-1);
363 decision_depth_ = current_pos_;
364 current_pos_ = local_current_pos;
365 ++v;
366 }
367 decision_depth_ = current_pos_;
368
369 if (v >= bound) {
370 current_pos_ = local_current_pos;
371 for (int i = current_pos_; i < CGOptions::max_exhaustive_depth(); ++i) {
372 states_[i]->set_init(false);
373 }
374 --decision_depth_;
375 if (decision_depth_ < 0)
376 all_done_ = true;
377 Error::set_error(BACKTRACKING_ERROR);
378 return -1;
379 }
380
381 state->set_value(v);
382
383 ERROR_GUARD(-1);
384
385 seq_->add_number(v, bound, local_current_pos);
386 return v;
387 }
388 }
389
390 void
log_depth(int d,const string * where,const char * log)391 DFSRndNumGenerator::log_depth(int d, const string *where, const char *log)
392 {
393 std::ostringstream ss1;
394
395 if (log)
396 ss1 << "[" << log << "]";
397
398 if (where)
399 ss1 << d << "(" << *where << ", pos = " << current_pos_ << ", current_decision_depth=" << decision_depth_ << ")->";
400 else
401 ss1 << d << "(..., pos = " << current_pos_ << ", current_decision_depth=" << decision_depth_ << ")->";
402 trace_string_ += ss1.str();
403 }
404
405 void
init_states(int size)406 DFSRndNumGenerator::init_states(int size)
407 {
408 for (int i = 0; i < size; ++i) {
409 DFSRndNumGenerator::SearchState *state = new SearchState(i);
410 assert(state && "new SearchState: error!");
411 states_.push_back(state);
412 }
413 }
414
415 void
reset_state(void)416 DFSRndNumGenerator::reset_state(void)
417 {
418 current_pos_ = -1;
419 trace_string_ = "";
420 seq_->clear();
421 }
422
423 /*
424 *
425 */
426 void
get_sequence(std::string & sequence)427 DFSRndNumGenerator::get_sequence(std::string &sequence)
428 {
429 std::ostringstream ss;
430 seq_->get_sequence(ss);
431 sequence = ss.str();
432 }
433
434 std::string
get_prefixed_name(const std::string & name)435 DFSRndNumGenerator::get_prefixed_name(const std::string &name)
436 {
437 std::ostringstream ss;
438 ss << "p_";
439 seq_->get_sequence(ss);
440 ss << seq_->get_sep_char() << name;
441 return ss.str();
442 }
443
444 /*
445 * Print the tracing information for debugging.
446 */
447 std::string &
trace_depth()448 DFSRndNumGenerator::trace_depth()
449 {
450 return trace_string_;
451 }
452
453 unsigned int
rnd_upto(const unsigned int n,const Filter * f,const std::string * where)454 DFSRndNumGenerator::rnd_upto(const unsigned int n, const Filter *f, const std::string *where)
455 {
456 int x = random_choice(n, f, where);
457 assert(x == -1 || (x >= 0 && x < static_cast<int>(n)));
458 return x;
459 }
460
461 bool
rnd_flipcoin(const unsigned int n,const Filter * f,const std::string * where)462 DFSRndNumGenerator::rnd_flipcoin(const unsigned int n, const Filter *f, const std::string *where)
463 {
464 vector<int> invalid;
465 int y;
466 if (n == 100) {
467 invalid.push_back(0);
468 y = random_choice(2, f, where, &invalid);
469 }
470 else if (n == 0) {
471 invalid.push_back(1);
472 y = random_choice(2, f, where, &invalid);
473 }
474 else {
475 y = random_choice(2, f, where);
476 }
477 assert(y == -1 || (y >= 0 && y < 2));
478 return y;
479 }
480
481 unsigned long
genrand(void)482 DFSRndNumGenerator::genrand(void)
483 {
484 return AbsRndNumGenerator::genrand();
485 }
486
487 std::string
RandomHexDigits(int num)488 DFSRndNumGenerator::RandomHexDigits( int num )
489 {
490 return AbsRndNumGenerator::RandomHexDigits(num);
491 }
492
493 std::string
RandomDigits(int num)494 DFSRndNumGenerator::RandomDigits( int num )
495 {
496 return AbsRndNumGenerator::RandomDigits(num);
497 }
498
499