1 // -*- mode: C++ -*-
2 //
3 // Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, 2014, 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 <cassert>
35 #include <iostream>
36 #include <sstream>
37 #include <vector>
38 
39 #include "SafeOpFlags.h"
40 #include "random.h"
41 #include "Error.h"
42 #include "Probabilities.h"
43 #include "DepthSpec.h"
44 #include "MspFilters.h"
45 #include "CGOptions.h"
46 
47 using namespace std;
48 
49 vector<string> SafeOpFlags::wrapper_names;
50 
SafeOpFlags()51 SafeOpFlags::SafeOpFlags()
52 {
53 	//Nothing to do
54 }
55 
SafeOpFlags(bool o1,bool o2,bool is_func,SafeOpSize osize)56 SafeOpFlags::SafeOpFlags(bool o1, bool o2, bool is_func, SafeOpSize osize)
57 	: op1_(o1),
58 	  op2_(o2),
59 	  is_func_(is_func),
60 	  op_size_(osize)
61 {
62 	//Nothing to do
63 }
64 
SafeOpFlags(const SafeOpFlags & flags)65 SafeOpFlags::SafeOpFlags(const SafeOpFlags &flags)
66 	: op1_(flags.op1_),
67 	  op2_(flags.op2_),
68 	  is_func_(flags.is_func_),
69 	  op_size_(flags.op_size_)
70 {
71 
72 }
73 
74 SafeOpFlags*
make_dummy_flags()75 SafeOpFlags::make_dummy_flags()
76 {
77 	return new SafeOpFlags(false, false, false, sInt8);
78 }
79 
80 eSimpleType
flags_to_type(bool sign,enum SafeOpSize size)81 SafeOpFlags::flags_to_type(bool sign, enum SafeOpSize size)
82 {
83 	if (sign) {
84 		switch(size) {
85 		case sInt8: return eChar;
86 		case sInt16: return eShort;
87 		case sInt32: return eInt;
88 		case sInt64: return eLongLong;
89 		case sFloat: return eFloat;
90 		default: assert(0); break;
91 		}
92 	}
93 	else {
94 		switch(size) {
95 		case sInt8: return eUChar;
96 		case sInt16: return eUShort;
97 		case sInt32: return eUInt;
98 		case sInt64: return eULongLong;
99 		default: assert(0); break;
100 		}
101 	}
102 	assert(0);
103 	return eInt;
104 }
105 
106 const Type*
get_lhs_type(void)107 SafeOpFlags::get_lhs_type(void)
108 {
109 	eSimpleType st = flags_to_type(op1_, op_size_);
110 	const Type& t = Type::get_simple_type(st);
111 	return &t;
112 }
113 
114 const Type*
get_rhs_type(void)115 SafeOpFlags::get_rhs_type(void)
116 {
117 	eSimpleType st = flags_to_type(op2_, op_size_);
118 	const Type& t = Type::get_simple_type(st);
119 	return &t;
120 }
121 
122 bool
return_float_type(const Type * rv_type,const Type * op1_type,const Type * op2_type,eBinaryOps bop)123 SafeOpFlags::return_float_type(const Type *rv_type, const Type *op1_type, const Type *op2_type,
124 				eBinaryOps bop)
125 {
126 	if (!CGOptions::enable_float())
127 		return false;
128 	if (rv_type && rv_type->is_float())
129 		return true;
130 	if ((op1_type && op1_type->is_float()) || (op2_type && op2_type->is_float()))
131 		return true;
132 	if (!FunctionInvocation::BinaryOpWorksForFloat(bop))
133 		return false;
134 	return false;
135 }
136 
137 bool
return_float_type(const Type * rv_type,const Type * op1_type,eUnaryOps uop)138 SafeOpFlags::return_float_type(const Type *rv_type, const Type *op1_type, eUnaryOps uop)
139 {
140 	if (!CGOptions::enable_float())
141 		return false;
142 	if (rv_type && rv_type->is_float())
143 		return true;
144 	if (op1_type && op1_type->is_float())
145 		return true;
146 	if (!FunctionInvocation::UnaryOpWorksForFloat(uop))
147 		return false;
148 	return false;
149 }
150 
151 
152 SafeOpFlags*
make_random_unary(const Type * rv_type,const Type * op1_type,eUnaryOps uop)153 SafeOpFlags::make_random_unary(const Type *rv_type, const Type *op1_type, eUnaryOps uop)
154 {
155 	SafeOpFlags *flags = new SafeOpFlags();
156 	assert("new SafeOpFlags fail!");
157 	bool rv_is_float = return_float_type(rv_type, op1_type, uop);
158 
159 	// floating point is always signed
160 	if (rv_is_float) {
161 		assert(FunctionInvocation::UnaryOpWorksForFloat(uop) && "Invalid unary op");
162 		flags->op1_ = true;
163 	}
164 	else {
165 		flags->op1_ = rnd_flipcoin(SafeOpsSignedProb);
166 	}
167 	flags->op2_ = flags->op1_;
168 
169 	// ISSUE: in the old code, is_func is always true
170 	// Probably need to be fixed later.
171 	flags->is_func_ = true;
172 
173 	MspSafeOpSizeFilter *filter = new MspSafeOpSizeFilter(MAX_BINARY_OP);
174 	Probabilities::register_extra_filter(pSafeOpsSizeProb, filter);
175 	if (rv_is_float) {
176 		assert(CGOptions::enable_float());
177 		flags->op_size_ = sFloat;
178 	}
179 	else {
180 		flags->op_size_ = (SafeOpSize)rnd_upto(MAX_SAFE_OP_SIZE-1, SAFE_OPS_SIZE_PROB_FILTER);
181 	}
182 	Probabilities::unregister_extra_filter(pSafeOpsSizeProb, filter);
183 
184 	delete filter;
185 	return flags;
186 }
187 
188 SafeOpFlags*
make_random_binary(const Type * rv_type,const Type * op1_type,const Type * op2_type,SafeOpKind op_kind,eBinaryOps bop)189 SafeOpFlags::make_random_binary(const Type *rv_type, const Type *op1_type, const Type *op2_type,
190 			SafeOpKind op_kind, eBinaryOps bop)
191 {
192 	DEPTH_GUARD_BY_TYPE_RETURN_WITH_FLAG(dtSafeOpFlags, op_kind, NULL);
193 	SafeOpFlags *flags = new SafeOpFlags();
194 	assert("new SafeOpFlags fail!");
195 	bool rv_is_float = return_float_type(rv_type, op1_type, op2_type, bop);
196 
197 	// floating point is always signed
198 	if (rv_is_float) {
199 		if (op_kind == sOpBinary) {
200 			assert(FunctionInvocation::BinaryOpWorksForFloat(bop) && "Invalid binary op");
201 		}
202 		flags->op1_ = true;
203 	}
204 	else {
205 		flags->op1_ = rnd_flipcoin(SafeOpsSignedProb);
206 	}
207 	ERROR_GUARD_AND_DEL1(NULL, flags);
208 
209 	if (op_kind == sOpBinary) {
210 		if (rv_is_float)
211 			flags->op2_ = true;
212 		else
213 			flags->op2_ = rnd_flipcoin(SafeOpsSignedProb);
214 		ERROR_GUARD_AND_DEL1(NULL, flags);
215 	}
216 	else {
217 		flags->op2_ = flags->op1_;
218 	}
219 
220 	// ISSUE: in the old code, is_func is always true
221 	// Probably need to be fixed later.
222 	flags->is_func_ = true;
223 
224 	MspSafeOpSizeFilter *filter = new MspSafeOpSizeFilter(bop);
225 	Probabilities::register_extra_filter(pSafeOpsSizeProb, filter);
226 
227 	if (rv_is_float) {
228 		assert(CGOptions::enable_float());
229 		flags->op_size_ = sFloat;
230 	}
231 	else {
232 		flags->op_size_ = (SafeOpSize)rnd_upto(MAX_SAFE_OP_SIZE-1, SAFE_OPS_SIZE_PROB_FILTER);
233 	}
234 	Probabilities::unregister_extra_filter(pSafeOpsSizeProb, filter);
235 	ERROR_GUARD_AND_DEL2(NULL, flags, filter);
236 
237 	//Probabilities::unregister_extra_filter(pSafeOpsSizeProb, filter);
238 	delete filter;
239 	return flags;
240 }
241 
242 SafeOpFlags *
clone() const243 SafeOpFlags::clone() const
244 {
245 	return new SafeOpFlags(*this);
246 }
247 
248 void
OutputSize(std::ostream & out) const249 SafeOpFlags::OutputSize(std::ostream &out) const
250 {
251 	if(!op1_)
252 		out << "u";
253 
254 	switch(op_size_) {
255 	case sInt8:
256 		out << "int8_t";
257 		break;
258 	case sInt16:
259 		out << "int16_t";
260 		break;
261 	case sInt32:
262 		out << "int32_t";
263 		break;
264 	case sInt64:
265 		out << "int64_t";
266 		break;
267 	case sFloat:
268 		out << "float";
269 		break;
270 	default:
271 		assert(!"invalid size!");
272 		break;
273 	}
274 }
275 
276 void
OutputFuncOrMacro(std::ostream & out) const277 SafeOpFlags::OutputFuncOrMacro(std::ostream &out) const
278 {
279 	is_func_ ? (out << "func_")
280 		: (out << "macro_");
281 }
282 
283 void
OutputSign(std::ostream & out,bool is_signed) const284 SafeOpFlags::OutputSign(std::ostream &out, bool is_signed) const
285 {
286 	is_signed ? (out << "_s")
287 		: (out << "_u");
288 }
289 
290 void
OutputOp1(std::ostream & out) const291 SafeOpFlags::OutputOp1(std::ostream &out) const
292 {
293 	OutputSign(out, op1_);
294 }
295 
296 void
OutputOp2(std::ostream & out) const297 SafeOpFlags::OutputOp2(std::ostream &out) const
298 {
299 	OutputSign(out, op2_);
300 }
301 
~SafeOpFlags()302 SafeOpFlags::~SafeOpFlags()
303 {
304 	// Nothing to do
305 }
306 
307 std::string
safe_float_func_string(enum eBinaryOps op) const308 SafeOpFlags::safe_float_func_string(enum eBinaryOps op) const
309 {
310 	string s;
311 	switch (op) {
312 		case eAdd: s = "safe_add_"; break;
313 		case eSub: s = "safe_sub_"; break;
314 		case eMul: s = "safe_mul_"; break;
315 		case eDiv: s = "safe_div_"; break;
316 		default: assert(0); break;
317 	}
318 	s += "func_float_f_f";
319 	return s;
320 
321 }
322 
323 /* find the safe math function/macro name */
324 std::string
to_string(enum eBinaryOps op) const325 SafeOpFlags::to_string(enum eBinaryOps op) const
326 {
327 	if (op_size_ == sFloat)
328 		return safe_float_func_string(op);
329 	string s;
330 	switch (op) {
331 		case eAdd: s = "safe_add_"; break;
332 		case eSub: s = "safe_sub_"; break;
333 		case eMul: s = "safe_mul_"; break;
334 		case eMod: s = "safe_mod_"; break;
335 		case eDiv: s = "safe_div_"; break;
336 		case eLShift: s = "safe_lshift_"; break;
337 		case eRShift: s = "safe_rshift_"; break;
338 		default: break;
339 	}
340 	ostringstream oss;
341 	OutputFuncOrMacro(oss);
342 	OutputSize(oss);
343 	OutputOp1(oss);
344 	(op == eLShift || op == eRShift) ? OutputOp2(oss) : OutputOp1(oss);
345 	s += oss.str();
346 	return s;
347 }
348 
349 /* find the safe math function/macro name */
350 std::string
to_string(enum eUnaryOps op) const351 SafeOpFlags::to_string(enum eUnaryOps op) const
352 {
353 	assert((op_size_ != sFloat) && "No safe unary function on floating point!");
354 	string s;
355 	switch (op) {
356 		case eMinus: s = "safe_unary_minus_"; break;
357 		default: break;
358 	}
359 	ostringstream oss;
360 	OutputFuncOrMacro(oss);
361 	OutputSize(oss);
362 	OutputOp1(oss);
363 	s += oss.str();
364 	return s;
365 }
366 
367 /* assign id to safe math function */
368 int
to_id(std::string fname)369 SafeOpFlags::to_id(std::string fname)
370 {
371 	for (size_t i=0; i<wrapper_names.size(); i++) {
372 		if (wrapper_names[i] == fname) {
373 			return i+1;
374 		}
375 	}
376 	wrapper_names.push_back(fname);
377 	return wrapper_names.size();
378 }
379