klee
Memory.cpp
Go to the documentation of this file.
1//===-- Memory.cpp --------------------------------------------------------===//
2//
3// The KLEE Symbolic Virtual Machine
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Memory.h"
11
12#include "Context.h"
13#include "ExecutionState.h"
14#include "MemoryManager.h"
15
16#include "klee/ADT/BitArray.h"
18#include "klee/Expr/Expr.h"
20#include "klee/Solver/Solver.h"
22
23#include "llvm/IR/Function.h"
24#include "llvm/IR/Instruction.h"
25#include "llvm/IR/Value.h"
26#include "llvm/Support/CommandLine.h"
27#include "llvm/Support/raw_ostream.h"
28
29#include <cassert>
30#include <sstream>
31
32using namespace llvm;
33using namespace klee;
34
35namespace {
36 cl::opt<bool>
37 UseConstantArrays("use-constant-arrays",
38 cl::desc("Use constant arrays instead of updates when possible (default=true)\n"),
39 cl::init(true),
40 cl::cat(SolvingCat));
41}
42
43/***/
44
45int MemoryObject::counter = 0;
46
47MemoryObject::~MemoryObject() {
48 if (parent)
49 parent->markFreed(this);
50}
51
52void MemoryObject::getAllocInfo(std::string &result) const {
53 llvm::raw_string_ostream info(result);
54
55 info << "MO" << id << "[" << size << "]";
56
57 if (allocSite) {
58 info << " allocated at ";
59 if (const Instruction *i = dyn_cast<Instruction>(allocSite)) {
60 info << i->getParent()->getParent()->getName() << "():";
61 info << *i;
62 } else if (const GlobalValue *gv = dyn_cast<GlobalValue>(allocSite)) {
63 info << "global:" << gv->getName();
64 } else {
65 info << "value:" << *allocSite;
66 }
67 } else {
68 info << " (no allocation info)";
69 }
70
71 info.flush();
72}
73
74/***/
75
77 : copyOnWriteOwner(0),
78 object(mo),
79 concreteStore(new uint8_t[mo->size]),
80 concreteMask(nullptr),
81 knownSymbolics(nullptr),
82 unflushedMask(nullptr),
83 updates(nullptr, nullptr),
84 size(mo->size),
85 readOnly(false) {
86 if (!UseConstantArrays) {
87 static unsigned id = 0;
88 const Array *array =
89 getArrayCache()->CreateArray("tmp_arr" + llvm::utostr(++id), size);
90 updates = UpdateList(array, 0);
91 }
92 memset(concreteStore, 0, size);
93}
94
95
97 : copyOnWriteOwner(0),
98 object(mo),
99 concreteStore(new uint8_t[mo->size]),
100 concreteMask(nullptr),
101 knownSymbolics(nullptr),
102 unflushedMask(nullptr),
103 updates(array, nullptr),
104 size(mo->size),
105 readOnly(false) {
106 makeSymbolic();
107 memset(concreteStore, 0, size);
108}
109
111 : copyOnWriteOwner(0),
112 object(os.object),
113 concreteStore(new uint8_t[os.size]),
114 concreteMask(os.concreteMask ? new BitArray(*os.concreteMask, os.size) : nullptr),
115 knownSymbolics(nullptr),
116 unflushedMask(os.unflushedMask ? new BitArray(*os.unflushedMask, os.size) : nullptr),
117 updates(os.updates),
118 size(os.size),
119 readOnly(false) {
120 assert(!os.readOnly && "no need to copy read only object?");
121 if (os.knownSymbolics) {
123 for (unsigned i=0; i<size; i++)
125 }
126
127 memcpy(concreteStore, os.concreteStore, size*sizeof(*concreteStore));
128}
129
131 delete concreteMask;
132 delete unflushedMask;
133 delete[] knownSymbolics;
134 delete[] concreteStore;
135}
136
138 assert(object && "object was NULL");
139 return object->parent->getArrayCache();
140}
141
142/***/
143
145 // Constant arrays are created lazily.
146 if (!updates.root) {
147 // Collect the list of writes, with the oldest writes first.
148
149 // FIXME: We should be able to do this more efficiently, we just need to be
150 // careful to get the interaction with the cache right. In particular we
151 // should avoid creating UpdateNode instances we never use.
152 unsigned NumWrites = updates.head ? updates.head->getSize() : 0;
153 std::vector< std::pair< ref<Expr>, ref<Expr> > > Writes(NumWrites);
154 const auto *un = updates.head.get();
155 for (unsigned i = NumWrites; i != 0; un = un->next.get()) {
156 --i;
157 Writes[i] = std::make_pair(un->index, un->value);
158 }
159
160 std::vector< ref<ConstantExpr> > Contents(size);
161
162 // Initialize to zeros.
163 for (unsigned i = 0, e = size; i != e; ++i)
164 Contents[i] = ConstantExpr::create(0, Expr::Int8);
165
166 // Pull off as many concrete writes as we can.
167 unsigned Begin = 0, End = Writes.size();
168 for (; Begin != End; ++Begin) {
169 // Push concrete writes into the constant array.
170 ConstantExpr *Index = dyn_cast<ConstantExpr>(Writes[Begin].first);
171 if (!Index)
172 break;
173
174 ConstantExpr *Value = dyn_cast<ConstantExpr>(Writes[Begin].second);
175 if (!Value)
176 break;
177
178 Contents[Index->getZExtValue()] = Value;
179 }
180
181 static unsigned id = 0;
182 const Array *array = getArrayCache()->CreateArray(
183 "const_arr" + llvm::utostr(++id), size, &Contents[0],
184 &Contents[0] + Contents.size());
185 updates = UpdateList(array, 0);
186
187 // Apply the remaining (non-constant) writes.
188 for (; Begin != End; ++Begin)
189 updates.extend(Writes[Begin].first, Writes[Begin].second);
190 }
191
192 return updates;
193}
194
196 const ExecutionState &state) const {
197 for (unsigned i = 0; i < size; i++) {
198 if (isByteKnownSymbolic(i)) {
200 bool success = solver->getValue(state.constraints, read8(i), ce,
201 state.queryMetaData);
202 if (!success)
203 klee_warning("Solver timed out when getting a value for external call, "
204 "byte %p+%u will have random value",
205 (void *)object->address, i);
206 else
207 ce->toMemory(concreteStore + i);
208 }
209 }
210}
211
213 delete concreteMask;
214 delete unflushedMask;
215 delete[] knownSymbolics;
216 concreteMask = nullptr;
217 unflushedMask = nullptr;
218 knownSymbolics = nullptr;
219}
220
222 assert(!updates.head &&
223 "XXX makeSymbolic of objects with symbolic values is unsupported");
224
225 // XXX simplify this, can just delete various arrays I guess
226 for (unsigned i=0; i<size; i++) {
228 setKnownSymbolic(i, 0);
230 }
231}
232
234 makeConcrete();
235 memset(concreteStore, 0, size);
236}
237
239 makeConcrete();
240 for (unsigned i=0; i<size; i++) {
241 // randomly selected by 256 sided die
242 concreteStore[i] = 0xAB;
243 }
244}
245
246/*
247Cache Invariants
248--
249isByteKnownSymbolic(i) => !isByteConcrete(i)
250isByteConcrete(i) => !isByteKnownSymbolic(i)
251isByteUnflushed(i) => (isByteConcrete(i) || isByteKnownSymbolic(i))
252 */
253
255 unsigned *base_r,
256 unsigned *size_r) const {
257 *base_r = 0;
258 *size_r = size;
259}
260
261void ObjectState::flushRangeForRead(unsigned rangeBase,
262 unsigned rangeSize) const {
263 if (!unflushedMask)
264 unflushedMask = new BitArray(size, true);
265
266 for (unsigned offset = rangeBase; offset < rangeBase + rangeSize; offset++) {
267 if (isByteUnflushed(offset)) {
268 if (isByteConcrete(offset)) {
271 } else {
272 assert(isByteKnownSymbolic(offset) &&
273 "invalid bit set in unflushedMask");
275 knownSymbolics[offset]);
276 }
277
278 unflushedMask->unset(offset);
279 }
280 }
281}
282
283void ObjectState::flushRangeForWrite(unsigned rangeBase, unsigned rangeSize) {
284 if (!unflushedMask)
285 unflushedMask = new BitArray(size, true);
286
287 for (unsigned offset = rangeBase; offset < rangeBase + rangeSize; offset++) {
288 if (isByteUnflushed(offset)) {
289 if (isByteConcrete(offset)) {
292 markByteSymbolic(offset);
293 } else {
294 assert(isByteKnownSymbolic(offset) &&
295 "invalid bit set in unflushedMask");
297 knownSymbolics[offset]);
298 setKnownSymbolic(offset, 0);
299 }
300
301 unflushedMask->unset(offset);
302 } else {
303 // flushed bytes that are written over still need
304 // to be marked out
305 if (isByteConcrete(offset)) {
306 markByteSymbolic(offset);
307 } else if (isByteKnownSymbolic(offset)) {
308 setKnownSymbolic(offset, 0);
309 }
310 }
311 }
312}
313
314bool ObjectState::isByteConcrete(unsigned offset) const {
315 return !concreteMask || concreteMask->get(offset);
316}
317
318bool ObjectState::isByteUnflushed(unsigned offset) const {
319 return !unflushedMask || unflushedMask->get(offset);
320}
321
322bool ObjectState::isByteKnownSymbolic(unsigned offset) const {
323 return knownSymbolics && knownSymbolics[offset].get();
324}
325
326void ObjectState::markByteConcrete(unsigned offset) {
327 if (concreteMask)
328 concreteMask->set(offset);
329}
330
331void ObjectState::markByteSymbolic(unsigned offset) {
332 if (!concreteMask)
333 concreteMask = new BitArray(size, true);
334 concreteMask->unset(offset);
335}
336
337void ObjectState::markByteUnflushed(unsigned offset) {
338 if (unflushedMask)
339 unflushedMask->set(offset);
340}
341
342void ObjectState::markByteFlushed(unsigned offset) {
343 if (!unflushedMask) {
344 unflushedMask = new BitArray(size, false);
345 } else {
346 unflushedMask->unset(offset);
347 }
348}
349
350void ObjectState::setKnownSymbolic(unsigned offset,
351 Expr *value /* can be null */) {
352 if (knownSymbolics) {
353 knownSymbolics[offset] = value;
354 } else {
355 if (value) {
357 knownSymbolics[offset] = value;
358 }
359 }
360}
361
362/***/
363
364ref<Expr> ObjectState::read8(unsigned offset) const {
365 if (isByteConcrete(offset)) {
367 } else if (isByteKnownSymbolic(offset)) {
368 return knownSymbolics[offset];
369 } else {
370 assert(!isByteUnflushed(offset) && "unflushed byte without cache value");
371
374 }
375}
376
378 assert(!isa<ConstantExpr>(offset) && "constant offset passed to symbolic read8");
379 unsigned base, size;
380 fastRangeCheckOffset(offset, &base, &size);
381 flushRangeForRead(base, size);
382
383 if (size>4096) {
384 std::string allocInfo;
385 object->getAllocInfo(allocInfo);
386 klee_warning_once(0, "flushing %d bytes on read, may be slow and/or crash: %s",
387 size,
388 allocInfo.c_str());
389 }
390
391 return ReadExpr::create(getUpdates(), ZExtExpr::create(offset, Expr::Int32));
392}
393
394void ObjectState::write8(unsigned offset, uint8_t value) {
395 //assert(read_only == false && "writing to read-only object!");
396 concreteStore[offset] = value;
397 setKnownSymbolic(offset, 0);
398
399 markByteConcrete(offset);
400 markByteUnflushed(offset);
401}
402
403void ObjectState::write8(unsigned offset, ref<Expr> value) {
404 // can happen when ExtractExpr special cases
405 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(value)) {
406 write8(offset, (uint8_t) CE->getZExtValue(8));
407 } else {
408 setKnownSymbolic(offset, value.get());
409
410 markByteSymbolic(offset);
411 markByteUnflushed(offset);
412 }
413}
414
416 assert(!isa<ConstantExpr>(offset) && "constant offset passed to symbolic write8");
417 unsigned base, size;
418 fastRangeCheckOffset(offset, &base, &size);
420
421 if (size>4096) {
422 std::string allocInfo;
423 object->getAllocInfo(allocInfo);
424 klee_warning_once(0, "flushing %d bytes on read, may be slow and/or crash: %s",
425 size,
426 allocInfo.c_str());
427 }
428
429 updates.extend(ZExtExpr::create(offset, Expr::Int32), value);
430}
431
432/***/
433
435 // Truncate offset to 32-bits.
436 offset = ZExtExpr::create(offset, Expr::Int32);
437
438 // Check for reads at constant offsets.
439 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(offset))
440 return read(CE->getZExtValue(32), width);
441
442 // Treat bool specially, it is the only non-byte sized write we allow.
443 if (width == Expr::Bool)
444 return ExtractExpr::create(read8(offset), 0, Expr::Bool);
445
446 // Otherwise, follow the slow general case.
447 unsigned NumBytes = width / 8;
448 assert(width == NumBytes * 8 && "Invalid read size!");
449 ref<Expr> Res(0);
450 for (unsigned i = 0; i != NumBytes; ++i) {
451 unsigned idx = Context::get().isLittleEndian() ? i : (NumBytes - i - 1);
452 ref<Expr> Byte = read8(AddExpr::create(offset,
454 Expr::Int32)));
455 Res = i ? ConcatExpr::create(Byte, Res) : Byte;
456 }
457
458 return Res;
459}
460
461ref<Expr> ObjectState::read(unsigned offset, Expr::Width width) const {
462 // Treat bool specially, it is the only non-byte sized write we allow.
463 if (width == Expr::Bool)
464 return ExtractExpr::create(read8(offset), 0, Expr::Bool);
465
466 // Otherwise, follow the slow general case.
467 unsigned NumBytes = width / 8;
468 assert(width == NumBytes * 8 && "Invalid width for read size!");
469 ref<Expr> Res(0);
470 for (unsigned i = 0; i != NumBytes; ++i) {
471 unsigned idx = Context::get().isLittleEndian() ? i : (NumBytes - i - 1);
472 ref<Expr> Byte = read8(offset + idx);
473 Res = i ? ConcatExpr::create(Byte, Res) : Byte;
474 }
475
476 return Res;
477}
478
480 // Truncate offset to 32-bits.
481 offset = ZExtExpr::create(offset, Expr::Int32);
482
483 // Check for writes at constant offsets.
484 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(offset)) {
485 write(CE->getZExtValue(32), value);
486 return;
487 }
488
489 // Treat bool specially, it is the only non-byte sized write we allow.
490 Expr::Width w = value->getWidth();
491 if (w == Expr::Bool) {
492 write8(offset, ZExtExpr::create(value, Expr::Int8));
493 return;
494 }
495
496 // Otherwise, follow the slow general case.
497 unsigned NumBytes = w / 8;
498 assert(w == NumBytes * 8 && "Invalid write size!");
499 for (unsigned i = 0; i != NumBytes; ++i) {
500 unsigned idx = Context::get().isLittleEndian() ? i : (NumBytes - i - 1);
501 write8(AddExpr::create(offset, ConstantExpr::create(idx, Expr::Int32)),
502 ExtractExpr::create(value, 8 * i, Expr::Int8));
503 }
504}
505
506void ObjectState::write(unsigned offset, ref<Expr> value) {
507 // Check for writes of constant values.
508 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(value)) {
509 Expr::Width w = CE->getWidth();
510 if (w <= 64 && klee::bits64::isPowerOfTwo(w)) {
511 uint64_t val = CE->getZExtValue();
512 switch (w) {
513 default: assert(0 && "Invalid write size!");
514 case Expr::Bool:
515 case Expr::Int8: write8(offset, val); return;
516 case Expr::Int16: write16(offset, val); return;
517 case Expr::Int32: write32(offset, val); return;
518 case Expr::Int64: write64(offset, val); return;
519 }
520 }
521 }
522
523 // Treat bool specially, it is the only non-byte sized write we allow.
524 Expr::Width w = value->getWidth();
525 if (w == Expr::Bool) {
526 write8(offset, ZExtExpr::create(value, Expr::Int8));
527 return;
528 }
529
530 // Otherwise, follow the slow general case.
531 unsigned NumBytes = w / 8;
532 assert(w == NumBytes * 8 && "Invalid write size!");
533 for (unsigned i = 0; i != NumBytes; ++i) {
534 unsigned idx = Context::get().isLittleEndian() ? i : (NumBytes - i - 1);
535 write8(offset + idx, ExtractExpr::create(value, 8 * i, Expr::Int8));
536 }
537}
538
539void ObjectState::write16(unsigned offset, uint16_t value) {
540 unsigned NumBytes = 2;
541 for (unsigned i = 0; i != NumBytes; ++i) {
542 unsigned idx = Context::get().isLittleEndian() ? i : (NumBytes - i - 1);
543 write8(offset + idx, (uint8_t) (value >> (8 * i)));
544 }
545}
546
547void ObjectState::write32(unsigned offset, uint32_t value) {
548 unsigned NumBytes = 4;
549 for (unsigned i = 0; i != NumBytes; ++i) {
550 unsigned idx = Context::get().isLittleEndian() ? i : (NumBytes - i - 1);
551 write8(offset + idx, (uint8_t) (value >> (8 * i)));
552 }
553}
554
555void ObjectState::write64(unsigned offset, uint64_t value) {
556 unsigned NumBytes = 8;
557 for (unsigned i = 0; i != NumBytes; ++i) {
558 unsigned idx = Context::get().isLittleEndian() ? i : (NumBytes - i - 1);
559 write8(offset + idx, (uint8_t) (value >> (8 * i)));
560 }
561}
562
563void ObjectState::print() const {
564 llvm::errs() << "-- ObjectState --\n";
565 llvm::errs() << "\tMemoryObject ID: " << object->id << "\n";
566 llvm::errs() << "\tRoot Object: " << updates.root << "\n";
567 llvm::errs() << "\tSize: " << size << "\n";
568
569 llvm::errs() << "\tBytes:\n";
570 for (unsigned i=0; i<size; i++) {
571 llvm::errs() << "\t\t["<<i<<"]"
572 << " concrete? " << isByteConcrete(i)
573 << " known-sym? " << isByteKnownSymbolic(i)
574 << " unflushed? " << isByteUnflushed(i) << " = ";
575 ref<Expr> e = read8(i);
576 llvm::errs() << e << "\n";
577 }
578
579 llvm::errs() << "\tUpdates:\n";
580 for (const auto *un = updates.head.get(); un; un = un->next.get()) {
581 llvm::errs() << "\t\t[" << un->index << "] = " << un->value << "\n";
582 }
583}
Provides an interface for creating and destroying Array objects.
Definition: ArrayCache.h:31
const Array * CreateArray(const std::string &_name, uint64_t _size, const ref< ConstantExpr > *constantValuesBegin=0, const ref< ConstantExpr > *constantValuesEnd=0, Expr::Width _domain=Expr::Int32, Expr::Width _range=Expr::Int8)
Create an Array object.
Definition: ArrayCache.cpp:20
bool get(unsigned idx)
Definition: BitArray.h:34
void unset(unsigned idx)
Definition: BitArray.h:36
void set(unsigned idx)
Definition: BitArray.h:35
static ref< Expr > create(const ref< Expr > &l, const ref< Expr > &r)
Definition: Expr.cpp:623
static ref< ConstantExpr > create(uint64_t v, Width w)
Definition: Expr.h:1079
uint64_t getZExtValue(unsigned bits=64) const
Definition: Expr.h:1030
bool isLittleEndian() const
Definition: Context.h:38
static const Context & get()
get - Return the global singleton instance of the Context.
Definition: Context.cpp:30
ExecutionState representing a path under exploration.
SolverQueryMetaData queryMetaData
Statistics and information.
ConstraintSet constraints
Constraints collected so far.
Class representing symbolic expressions.
Definition: Expr.h:91
static const Width Int64
Definition: Expr.h:104
static const Width Int32
Definition: Expr.h:103
virtual Width getWidth() const =0
unsigned Width
The type of an expression is simply its width, in bits.
Definition: Expr.h:97
static const Width Int16
Definition: Expr.h:102
static const Width Bool
Definition: Expr.h:100
static const Width Int8
Definition: Expr.h:101
static ref< Expr > create(ref< Expr > e, unsigned bitOff, Width w)
Creates an ExtractExpr with the given bit offset and width.
Definition: Expr.cpp:675
void markFreed(MemoryObject *mo)
unsigned size
size in bytes
Definition: Memory.h:52
void getAllocInfo(std::string &result) const
Get an identifying string for this allocation.
Definition: Memory.cpp:52
MemoryManager * parent
Definition: Memory.h:61
const llvm::Value * allocSite
Definition: Memory.h:66
ref< Expr > read8(unsigned offset) const
Definition: Memory.cpp:364
UpdateList updates
Definition: Memory.h:190
void initializeToZero()
Make contents all concrete and zero.
Definition: Memory.cpp:233
ref< Expr > read(ref< Expr > offset, Expr::Width width) const
Definition: Memory.cpp:434
void flushRangeForRead(unsigned rangeBase, unsigned rangeSize) const
Definition: Memory.cpp:261
void markByteConcrete(unsigned offset)
Definition: Memory.cpp:326
void write64(unsigned offset, uint64_t value)
Definition: Memory.cpp:555
ref< const MemoryObject > object
Definition: Memory.h:173
void write8(unsigned offset, uint8_t value)
Definition: Memory.cpp:394
BitArray * unflushedMask
Definition: Memory.h:187
ArrayCache * getArrayCache() const
Definition: Memory.cpp:137
void initializeToRandom()
Make contents all concrete and random.
Definition: Memory.cpp:238
void setKnownSymbolic(unsigned offset, Expr *value)
Definition: Memory.cpp:350
const UpdateList & getUpdates() const
Definition: Memory.cpp:144
void write16(unsigned offset, uint16_t value)
Definition: Memory.cpp:539
void flushRangeForWrite(unsigned rangeBase, unsigned rangeSize)
Definition: Memory.cpp:283
void print() const
Definition: Memory.cpp:563
void markByteFlushed(unsigned offset)
Definition: Memory.cpp:342
void write(unsigned offset, ref< Expr > value)
Definition: Memory.cpp:506
void markByteSymbolic(unsigned offset)
Definition: Memory.cpp:331
void markByteUnflushed(unsigned offset)
Definition: Memory.cpp:337
bool isByteConcrete(unsigned offset) const
isByteConcrete ==> !isByteKnownSymbolic
Definition: Memory.cpp:314
void fastRangeCheckOffset(ref< Expr > offset, unsigned *base_r, unsigned *size_r) const
Definition: Memory.cpp:254
void write32(unsigned offset, uint32_t value)
Definition: Memory.cpp:547
unsigned size
Definition: Memory.h:193
uint8_t * concreteStore
Holds all known concrete bytes.
Definition: Memory.h:176
bool isByteUnflushed(unsigned offset) const
isByteUnflushed(i) => (isByteConcrete(i) || isByteKnownSymbolic(i))
Definition: Memory.cpp:318
ObjectState(const MemoryObject *mo)
Definition: Memory.cpp:76
void flushToConcreteStore(TimingSolver *solver, const ExecutionState &state) const
Definition: Memory.cpp:195
BitArray * concreteMask
concreteMask[byte] is set if byte is known to be concrete
Definition: Memory.h:179
bool isByteKnownSymbolic(unsigned offset) const
isByteKnownSymbolic ==> !isByteConcrete
Definition: Memory.cpp:322
void makeConcrete()
Definition: Memory.cpp:212
ref< Expr > * knownSymbolics
Definition: Memory.h:183
void makeSymbolic()
Definition: Memory.cpp:221
static ref< Expr > create(const UpdateList &updates, ref< Expr > i)
Definition: Expr.cpp:538
bool getValue(const ConstraintSet &, ref< Expr > expr, ref< ConstantExpr > &result, SolverQueryMetaData &metaData)
Class representing a complete list of updates into an array.
Definition: Expr.h:539
void extend(const ref< Expr > &index, const ref< Expr > &value)
Definition: Updates.cpp:51
ref< UpdateNode > head
pointer to the most recent update node
Definition: Expr.h:546
const Array * root
Definition: Expr.h:543
T * get() const
Definition: Ref.h:129
uint64_t isPowerOfTwo(uint64_t x)
Definition: Bits.h:91
Definition: main.cpp:291
llvm::cl::OptionCategory SolvingCat
void void void void klee_warning_once(const void *id, const char *msg,...) __attribute__((format(printf
void void void klee_warning(const char *msg,...) __attribute__((format(printf