Predator  [unstable] git snapshot
symheap.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009-2011 Kamil Dudka <kdudka@redhat.com>
3  * Copyright (C) 2010 Petr Peringer, FIT
4  *
5  * This file is part of predator.
6  *
7  * predator is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * any later version.
11  *
12  * predator is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with predator. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef H_GUARD_SYM_HEAP_H
22 #define H_GUARD_SYM_HEAP_H
23 
24 /**
25  * @file symheap.hh
26  * SymHeap - the elementary representation of the state of program memory
27  */
28 
29 #include "config.h"
30 
31 #include "intrange.hh"
32 #include "symid.hh"
33 #include "util.hh"
34 
35 #include <cl/code_listener.h>
36 
37 #include <map> // for TValMap
38 #include <set> // for TCVarSet
39 #include <string>
40 #include <vector> // for many types
41 
42 class SymBackTrace;
43 
44 /// classification of kind of origins a value may come from
46  VO_INVALID, ///< reserved for signalling error states
47  VO_ASSIGNED, ///< known result of an operation
48  VO_UNKNOWN, ///< value was abstracted out and guessed later on
49  VO_REINTERPRET, ///< a result of unsupported data reinterpretation
50  VO_DEREF_FAILED, ///< a result of invalid dereference
51  VO_STACK, ///< untouched contents of stack
52  VO_HEAP ///< untouched contents of heap
53 };
54 
55 /// true for VO_HEAP and VO_STACK
57 
58 /// classification of kind of objects a value may point to
60  VT_INVALID, ///< completely invalid target
61  VT_UNKNOWN, ///< arbitrary target
62  VT_COMPOSITE, ///< value of a composite field (not a pointer to!)
63  VT_CUSTOM, ///< non-pointer data, classified by ECustomValue
64  VT_OBJECT, ///< target is a (possibly invalid) object
65 
66  // TODO: drop this?
67  VT_RANGE ///< an offset value where offset is given by range
68 };
69 
70 /// TODO: drop this!
72 
73 /// classification of the storage class for objects
75  SC_INVALID, ///< reserved for signalling error states
76  SC_UNKNOWN, ///< no assumptions, the object may be even shared
77  SC_STATIC, ///< safely allocated in static data if not a 0+ obj
78  SC_ON_HEAP, ///< safely allocated on heap except for 0+ objects
79  SC_ON_STACK ///< safely allocated on stack except for 0+ objects
80 };
81 
82 /// true for SC_ON_HEAP
84 
85 /// true for SC_STATIC and SC_ON_STACK
87 
88 /// classification of the target of an address (a.k.a. target specifier)
90  TS_INVALID, ///< reserved for signalling error states
91  TS_REGION, ///< the only allowed TS for addresses of regions
92  TS_FIRST, ///< target is the first node of an abstract object
93  TS_LAST, ///< target is the last node of an abstract object
94  TS_ALL ///< target is any node of an abstract object
95 };
96 
97 /// enumeration of custom values, such as integer literals, or code pointers
99  CV_INVALID, ///< reserved for signalling error states
100  CV_FNC, ///< code pointer
101  CV_INT_RANGE, ///< a closed interval over integral domain
102  CV_REAL, ///< floating-point number
103  CV_STRING ///< string literal
104 };
105 
107  int uid; ///< unique ID as assigned by Code Listener
108  double fpn; ///< floating-point number
109  std::string *str; ///< string literal
110  IR::Range rng; ///< closed interval over integral domain
111 };
112 
113 /// representation of a custom value, such as integer literal, or code pointer
114 class CustomValue {
115  public:
116  // cppcheck-suppress uninitVar
119  {
120  }
121 
122  ~CustomValue();
123  CustomValue(const CustomValue &);
125 
126  explicit CustomValue(int uid):
127  code_(CV_FNC)
128  {
129  data_.uid = uid;
130  }
131 
132  explicit CustomValue(const IR::Range &rng):
134  {
135  data_.rng = rng;
136  }
137 
138  explicit CustomValue(const double fpn):
139  code_(CV_REAL)
140  {
141  data_.fpn = fpn;
142  }
143 
144  explicit CustomValue(const char *str):
146  {
147  data_.str = new std::string(str);
148  }
149 
150  /// custom value classification
151  ECustomValue code() const {
152  return code_;
153  }
154 
155  /// unique ID as assigned by Code Listener (only for CV_FNC)
156  int uid() const;
157 
158  /// closed interval over integral domain (only for CV_INT_RANGE)
159  IR::Range& rng();
160 
161  /// closed interval over integral domain (only for CV_INT_RANGE)
162  const IR::Range& rng() const {
163  return const_cast<CustomValue *>(this)->rng();
164  }
165 
166  /// floating-point number (only for CV_REAL)
167  double fpn() const;
168 
169  /// string literal (only for CV_STRING)
170  const std::string &str() const;
171 
172  private:
173  friend bool operator==(const CustomValue &, const CustomValue &);
174 
177 };
178 
179 bool operator==(const CustomValue &a, const CustomValue &b);
180 
181 inline bool operator!=(const CustomValue &a, const CustomValue &b)
182 {
183  return !operator==(a, b);
184 }
185 
186 namespace CodeStorage {
187  struct Storage;
188 }
189 
190 namespace Trace {
191  class Node;
192 }
193 
194 /// a type used for integral offsets (changing this is known to cause problems)
196 
197 /// a type used for block sizes (do not set this to anything else than TOffset)
199 
200 /// a type used for block size ranges (do not try to change this one either)
202 
203 /// a container to store offsets to
204 typedef std::vector<TOffset> TOffList;
205 
206 /// container used to store value IDs to
207 typedef std::vector<TValId> TValList;
208 
209 /// container used to store object IDs to
210 typedef std::vector<TObjId> TObjList;
211 
212 /// container used to store value IDs to
213 typedef std::set<TValId> TValSet;
214 
215 /// container used to store object IDs to
216 typedef std::set<TObjId> TObjSet;
217 
218 /// a type used for (injective) value IDs mapping
219 typedef std::map<TValId, TValId> TValMap;
220 
221 /// a type used for (injective) object IDs mapping
222 typedef std::map<TObjId, TObjId> TObjMap;
223 
224 /// a type used for type-info
225 typedef const struct cl_type *TObjType;
226 
227 /// a class of type (structure, pointer, union, ...)
228 typedef enum cl_type_e TObjCode;
229 
230 /// a reference to CodeStorage::Storage instance describing the analyzed code
232 
233 /// a type used for prototype level (0 means not a prototype)
234 typedef short TProtoLevel;
235 
236 /**
237  * bundles static identification of a variable with its instance number
238  *
239  * In order to enable call recursion, we need to distinguish among various
240  * instances of the same automatic variable in case a function is called
241  * recursively.
242  */
243 struct CVar {
244  /// static identification of a variable
245  int uid;
246 
247  /// zero for global/static variables, instance number 1..n otherwise
248  int inst;
249 
250  CVar():
251  uid(-1),
252  inst(-1)
253  {
254  }
255 
256  CVar(int uid_, int inst_):
257  uid(uid_),
258  inst(inst_)
259  {
260  }
261 };
262 
263 inline bool operator==(const CVar &a, const CVar &b)
264 {
265  if (a.uid != b.uid)
266  return false;
267 
268  if (-1 == a.uid)
269  // do not match .inst when a.uid == -1 == b.uid
270  return true;
271 
272  return a.inst == b.inst;
273 }
274 
275 inline bool operator!=(const CVar &a, const CVar &b)
276 {
277  return !operator==(a, b);
278 }
279 
280 /// bundles static identification of a function with its call instance number
281 struct CallInst {
282  int uid; ///< uid of the function
283  int inst; ///< how many instances of the fnc we have on the stack
284 
285  CallInst(const SymBackTrace *);
286 
287  CallInst(int uid_, int inst_):
288  uid(uid_),
289  inst(inst_)
290  {
291  }
292 };
293 
294 /**
295  * lexicographical comparison of CallInst objects
296  * @note we need it in order to place the objects into ordered containers
297  */
298 inline bool operator<(const CallInst &a, const CallInst &b)
299 {
300  if (a.uid < b.uid)
301  return true;
302  else if (b.uid < a.uid)
303  return false;
304  else
305  // we know (a.uid == b.uid) at this point, let's compare .inst
306  return a.inst < b.inst;
307 }
308 
309 /// a list of _program_ variables
310 typedef std::vector<CVar> TCVarList;
311 
312 /// a set of _program_ variables
313 typedef std::set<CVar> TCVarSet;
314 
315 /// only uninitialized or nullified blocks; generic arrays and strings need more
316 struct UniformBlock {
317  TOffset off; ///< relative placement of the block wrt. the root
318  TSizeOf size; ///< size of the block in bytes
319  TValId tplValue; ///< value you need to clone on object instantiation
320 };
321 
322 /// a container used to return list of uniform blocks
323 typedef std::map<TOffset, UniformBlock> TUniBlockMap;
324 
325 /**
326  * lexicographical comparison of CVar objects
327  * @note we need it in order to place the objects into ordered containers
328  */
329 inline bool operator<(const CVar &a, const CVar &b)
330 {
331  if (a.uid < b.uid)
332  return true;
333  else if (b.uid < a.uid)
334  return false;
335  else
336  // we know (a.uid == b.uid) at this point, let's compare .inst
337  return a.inst < b.inst;
338 }
339 
340 class FldList;
341 
342 /// SymHeapCore - the elementary representation of the state of program memory
343 class SymHeapCore {
344  public:
345  /// create an empty symbolic heap
347 
348  /// destruction of the symbolic heap invalidates all IDs of its entities
349  virtual ~SymHeapCore();
350 
351  /// relatively cheap operation as long as SH_COPY_ON_WRITE is enabled
352  SymHeapCore(const SymHeapCore &);
353 
354  /// relatively cheap operation as long as SH_COPY_ON_WRITE is enabled
356 
357  /// exchange the contents with the other heap (works in constant time)
358  virtual void swap(SymHeapCore &);
359 
360  /// each symbolic heap is associated with a CodeStorage model of code
361  TStorRef stor() const { return stor_; }
362 
363  /// each symbolic heap is associated with a trace graph node
364  Trace::Node* traceNode() const;
365 
366  /// update the current trace graph node that the heap is associated with
367  void traceUpdate(Trace::Node *);
368 
369  /// the last assigned ID of a heap entity (not necessarily still valid)
370  unsigned lastId() const;
371 
372  public:
373  /**
374  * collect all objects having the given value inside
375  * @param dst reference to a container to store the result to
376  * @param val ID of the value to look for
377  * @param liveOnly if true, exclude objects that are no longer alive
378  * @note The operation may return from 0 to n objects.
379  */
380  void usedBy(FldList &dst, TValId val, bool liveOnly = false) const;
381 
382  /// return how many objects have the value inside
383  unsigned usedByCount(TValId val) const;
384 
385  /// return all objects that point at/inside the given object
386  void pointedBy(FldList &dst, TObjId) const;
387 
388  /// return how many objects point at/inside the given object
389  unsigned pointedByCount(TObjId) const;
390 
391  /// write an uninitialized or nullified block of memory
392  void writeUniformBlock(
393  const TObjId obj,
394  const UniformBlock &ub,
395  TValSet *killedPtrs = 0);
396 
397  /// copy 'size' bytes of raw memory from 'src' to 'dst'
399  const TValId dst,
400  const TValId src,
401  const TSizeOf size,
402  TValSet *killedPtrs = 0);
403 
404  public:
405  /// define an explicit Neq predicate
406  void addNeq(TValId v1, TValId v2);
407 
408  /// remove an explicit Neq predicate if defined
409  void delNeq(TValId v1, TValId v2);
410 
411  /// true if there is an @b explicit Neq relation over the given values
412  bool chkNeq(TValId v1, TValId v2) const;
413 
414  /// collect values connect with the given value via an extra predicate
415  void gatherRelatedValues(TValList &dst, TValId val) const;
416 
417  /// transfer as many as possible extra heap predicates from this to dst
418  void copyRelevantPreds(SymHeapCore &dst, const TValMap &valMap) const;
419 
420  /// true if all Neq predicates can be mapped to Neq predicates in ref
421  bool matchPreds(
422  const SymHeapCore &ref,
423  const TValMap &valMap,
424  const bool nonZeroOnly = false)
425  const;
426 
427  public:
428  /// translate the given address by the given offset
429  TValId valByOffset(TValId, TOffset offset);
430 
431  /// create (or recycle) a VT_RANGE value at the given allocated address
432  TValId valByRange(TValId at, IR::Range range);
433 
434  /// translate the given value by the given offset
435  TValId valShift(TValId valToShift, TValId shiftBy);
436 
437  /// classify the object the given value points to
439 
440  /// classify where the given value originates from
442 
443  /// return the target specifier of the given address
444  ETargetSpecifier targetSpec(TValId addr) const;
445 
446  /// return the object that the given address points to
447  TObjId objByAddr(TValId addr) const;
448 
449  /// classify the storage class of the given object
451 
452  /// return size (in bytes) of the given object
453  TSizeRange objSize(TObjId) const;
454 
455  /// target address at the given object with target specifier and offset
457 
458  public:
459  /// return the address of the root which the given value is binded to
460  TValId valRoot(TValId) const;
461 
462  /// return the relative placement from the root
463  TOffset valOffset(TValId) const;
464 
465  /// return the offset range associated with the given VT_RANGE value
467 
468  /// narrow down the offset range of the given VT_RANGE value
469  void valRestrictRange(TValId, IR::Range win);
470 
471  /// difference between two pointers (makes sense only for shared roots)
472  TValId diffPointers(const TValId v1, const TValId v2);
473 
474  /// return count of bytes (including NULL) we can safely read as string
476 
477  /// return the region corresponding to the given program variable
478  TObjId regionByVar(CVar, bool createIfNeeded);
479 
480  /// clone the given object, including the outgoing has-value edges
481  virtual TObjId objClone(TObjId);
482 
483  public:
484  /// replace all occurrences of val by replaceBy
485  virtual void valReplace(TValId val, TValId replaceBy);
486 
487  /// return the list of objects satisfying the given filtering predicate
488  void gatherObjects(TObjList &dst, bool (*)(EStorageClass) = 0) const;
489 
490  /// list of live fields (including ptrs) inside the given object
491  void gatherLiveFields(FldList &dst, TObjId) const;
492 
493  /// list of live pointers inside the give object
494  void gatherLivePointers(FldList &dst, TObjId) const;
495 
496  /// list of uninitialized and nullified uniform blocks of the given obj
497  void gatherUniformBlocks(TUniBlockMap &dst, TObjId) const;
498 
499  /// experimental optimization of joinUniBlocksCore()
501  TUniBlockMap *pCovered,
502  const TObjId root,
503  UniformBlock block)
504  const;
505 
506  /// return program variable that the given object maps to
507  CVar cVarByObject(TObjId) const;
508 
509  /**
510  * composite object given by val (applicable only on VT_COMPOSITE vals)
511  * @todo should we operate on FldHandle instead?
512  */
513  TFldId valGetComposite(TValId val) const;
514 
515  public:
516  /// allocate a chunk of stack of known size from the select call stack
517  TObjId stackAlloc(const TSizeRange &size, const CallInst &from);
518 
519  /// clear the list of anonymous stack objects of the given call instance
520  void clearAnonStackObjects(TObjList &dst, const CallInst &of);
521 
522  /// allocate a chunk of heap of known size
523  TObjId heapAlloc(const TSizeRange &size);
524 
525  /// return true if the given object can be still accessed safely
526  bool isValid(TObjId) const;
527 
528  /// invalidate the given object
529  virtual void objInvalidate(TObjId);
530 
531  /// update the estimated type-info of the given object
532  void objSetEstimatedType(TObjId obj, TObjType clt);
533 
534  /// return the estimated type-info of the given object
535  TObjType objEstimatedType(TObjId obj) const;
536 
537  /// create a @b generic value, otherwise use addrOfTarget()
539 
540  /// wrap a custom value, such as integer literal, or code pointer
542 
543  /// unwrap a custom value, such as integer literal, or code pointer
544  const CustomValue& valUnwrapCustom(TValId) const;
545 
546  public:
547  /// prototype level of the given object (0 means not a prototype)
549 
550  /// set prototype level of the given boject (0 means not a prototype)
551  void objSetProtoLevel(TObjId obj, TProtoLevel level);
552 
553  protected:
554  /// return a @b data pointer inside the given object at the given offset
555  TFldId ptrLookup(TObjId obj, TOffset off);
556 
557  /// return a field of the specified type at the specified offset in obj
558  TFldId fldLookup(TObjId obj, TOffset off, TObjType clt);
559 
560  /// increment the external reference count of the given object
561  void fldEnter(TFldId);
562 
563  /// decrement the external reference count (may trigger its destruction)
564  void fldLeave(TFldId);
565 
566  /// FldHandle takes care of external reference count
567  friend class FldHandle;
568  friend class PtrHandle;
569 
570  protected:
571  // these should be accessed indirectly via FldHandle
572  TValId valueOf(TFldId fld);
573  TValId placedAt(TFldId fld);
574  TObjId objByField(TFldId fld) const;
575  TOffset fieldOffset(TFldId fld) const;
576  TObjType fieldType(TFldId fld) const;
577  void setValOfField(TFldId fld, TValId val, TValSet *killedPtrs = 0);
578 
579  protected:
581 
582  private:
583  struct Private;
584  Private *d;
585 };
586 
587 class FldHandle {
588  public:
590  sh_(0),
592  {
593  }
594 
595  FldHandle(SymHeapCore &sh, TObjId obj, TObjType clt, TOffset off = 0):
596  sh_(&sh),
597  id_(sh.fldLookup(obj, off, clt))
598  {
599  if (0 < id_)
600  sh_->fldEnter(id_);
601  }
602 
603  explicit FldHandle(const TFldId special):
604  sh_(0),
605  id_(special)
606  {
607  CL_BREAK_IF(0 < special);
608  }
609 
610  FldHandle(const FldHandle &tpl):
611  sh_(tpl.sh_),
612  id_(tpl.id_)
613  {
614  if (0 < id_)
615  sh_->fldEnter(id_);
616  }
617 
619  sh_(&sh),
620  id_(tpl.id_)
621  {
622  if (0 < id_)
623  sh_->fldEnter(id_);
624  }
625 
627  if (0 < id_)
628  sh_->fldLeave(id_);
629  }
630 
632  if (0 < id_)
633  sh_->fldLeave(id_);
634 
635  sh_ = tpl.sh_;
636  id_ = tpl.id_;
637  if (0 < id_)
638  sh_->fldEnter(id_);
639 
640  return *this;
641  }
642 
643  public:
644  /// return the SymHeapCore instance associated with this handle
645  SymHeapCore* sh() const { return sh_; }
646 
647  /// return raw field ID inside this handle (used mainly internally)
648  TFldId fieldId() const { return id_; }
649 
650  /// true if the given handle is valid (does not imply field validity)
651  bool isValidHandle() const { return (0 < id_); }
652 
653  /// return the object that the field is part of
654  TObjId obj() const { return sh_->objByField(id_); }
655 
656  /// return the offset at which the field is placed within the object
657  TOffset offset() const { return sh_->fieldOffset(id_); }
658 
659  /// return the value inside the field (may trigger its initialization)
660  TValId value() const { return sh_->valueOf(id_); }
661 
662  /// return the address of the field (may trigger address instantiation)
663  TValId placedAt() const { return sh_->placedAt(id_); }
664 
665  /// static type-info of the given object (return 0 if not available)
666  TObjType type() const {
667  return (this->isValidHandle())
668  ? sh_->fieldType(id_)
669  : 0;
670  }
671 
672  /// assign the given value, caller is responsible for garbage collecting
673  void setValue(const TValId val, TValSet *killedPtrs = 0) const {
674  sh_->setValOfField(id_, val, killedPtrs);
675  }
676 
677  protected:
679  sh_(&sh),
680  id_(id)
681  {
682  if (0 < id_)
683  sh_->fldEnter(id_);
684  }
685 
686  friend class SymHeapCore;
687 
688  // TODO: remove this
689  friend class SymProc;
690 
691  // TODO: remove this
692  friend const char* valNullLabel(const SymHeapCore &, const TFldId);
693 
694  protected:
697 };
698 
699 /// this allows to insert FldHandle instances into std::set
700 inline bool operator<(const FldHandle &a, const FldHandle &b)
701 {
702  if (a.sh() < b.sh())
703  return true;
704 
705  if (b.sh() < a.sh())
706  return false;
707 
708  return (a.fieldId() < b.fieldId());
709 }
710 
711 inline bool operator==(const FldHandle &a, const FldHandle &b)
712 {
713  return (a.sh() == b.sh())
714  && (a.fieldId() == b.fieldId());
715 }
716 
717 inline bool operator!=(const FldHandle &a, const FldHandle &b)
718 {
719  return !operator==(a, b);
720 }
721 
722 class PtrHandle: public FldHandle {
723  public:
724  PtrHandle(SymHeapCore &sh, const TObjId obj, const TOffset off = 0):
725  FldHandle(sh, sh.ptrLookup(obj, off))
726  {
727  if (0 < id_)
728  sh_->fldEnter(id_);
729  }
730 };
731 
732 /// ugly, but typedefs do not support partial declarations
733 class FldList: public std::vector<FldHandle> { };
734 
735 /// set of object handles
736 typedef std::set<FldHandle> TFldSet;
737 
738 /// a type used for minimal segment length (0+, 1+, ...)
739 typedef short TMinLen;
740 
741 /// enumeration of abstract object (although OK_REGION is not abstract)
742 enum EObjKind {
743  OK_REGION = 0, ///< concrete object (not a segment)
744  OK_SLS, ///< singly-linked list segment
745  OK_DLS, ///< doubly-linked list segment
746  OK_OBJ_OR_NULL, ///< 0..1 object, assume NULL if not allocated
747  OK_SEE_THROUGH, ///< 0..1 object, see through if not allocated
748  OK_SEE_THROUGH_2N ///< OK_SEE_THROUGH with two next pointers
749 };
750 
751 inline bool isMayExistObj(const enum EObjKind kind)
752 {
753  switch (kind) {
754  case OK_OBJ_OR_NULL:
755  case OK_SEE_THROUGH:
756  case OK_SEE_THROUGH_2N:
757  return true;
758 
759  default:
760  return false;
761  }
762 }
763 
764 /// tuple of binding offsets assigned to abstract objects
765 struct BindingOff {
766  TOffset head; ///< target offset
767  TOffset next; ///< offset of the 'next' or 'r' pointer
768  TOffset prev; ///< offset of the 'prev' or 'l' pointer
769 
771  head(0),
772  next(0),
773  prev(0)
774  {
775  }
776 
778  head(-1),
779  next(-1),
780  prev(-1)
781  {
782  CL_BREAK_IF(OK_OBJ_OR_NULL != kind);
783  (void) kind;
784  }
785 };
786 
787 /// point-wise comparison of BindingOff
788 inline bool operator==(const BindingOff &off1, const BindingOff &off2)
789 {
790  return off1.head == off2.head
791  && off1.next == off2.next
792  && off1.prev == off2.prev;
793 }
794 
795 /// point-wise comparison of BindingOff
796 inline bool operator!=(const BindingOff &off1, const BindingOff &off2)
797 {
798  return !operator==(off1, off2);
799 }
800 
801 /// extension of SymHeapCore dealing with abstract objects (list segments etc.)
802 class SymHeap: public SymHeapCore {
803  public:
804  /// create an empty symbolic heap
806 
807  /// destruction of the symbolic heap invalidates all IDs of its entities
808  virtual ~SymHeap();
809 
810  /// relatively cheap operation as long as SH_COPY_ON_WRITE is enabled
811  SymHeap(const SymHeap &);
812 
813  /// relatively cheap operation as long as SH_COPY_ON_WRITE is enabled
814  SymHeap& operator=(const SymHeap &);
815 
816  virtual void swap(SymHeapCore &);
817 
818  public:
819  /// kind of object (region, SLS, DLS, ...)
820  EObjKind objKind(TObjId) const;
821 
822  /// tuple of binding offsets (next, prev, ...)
823  const BindingOff& segBinding(TObjId seg) const;
824 
825  /// set properties of an abstract object, set abstract if not already
826  void objSetAbstract(
827  TObjId seg,
828  EObjKind kind,
829  const BindingOff &off);
830 
831  /// set the given abstract object to be a concrete object (drops props)
832  void objSetConcrete(TObjId);
833 
834  /// read the minimal segment length of the given abstract object
835  TMinLen segMinLength(TObjId seg) const;
836 
837  /// assign the minimal segment length of the given abstract object
838  void segSetMinLength(TObjId seg, TMinLen len);
839 
840  public:
841  // just overrides (inherits the dox)
843  virtual void objInvalidate(TObjId);
844  virtual TObjId objClone(TObjId);
845 
846  private:
847  struct Private;
848  Private *d;
849 };
850 
851 /// enable/disable built-in self-checks (takes effect only in debug build)
852 void enableProtectedMode(bool enable);
853 
854 /// temporarily disable protected mode of SymHeap in a debug build
856  public:
858  enableProtectedMode(false);
859  }
860 
862  enableProtectedMode(true);
863  }
864 };
865 
866 #endif /* H_GUARD_SYM_HEAP_H */