]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_utilities/lib/walkers.h
2 * Copyright (c) 2000-2006,2011-2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // walkers - facilities for traversing and manipulating recursive data structures
28 // Very briefly, this facility allows for deep traversals of (potentially) recursive
29 // data structures through templated structure "walkers." Standard operations include
30 // deep copying to a contiguous memory buffer, size calculation, deep freeing, reconstitution
31 // after relocation (e.g. via IPC), and others. You can add other operations (e.g. scattered deep
32 // copy, debug dumping, etc.) by defining operations classes and applying them to the
33 // existing walkers. You can also extend the reach of the facility to new data structures
34 // by writing appropriate walker functions for them.
36 // NOTE: We no longer have a default walker for flat structures. You must define
37 // a walk(operate, foo * &) function for every data type encountered during a walk
38 // or you will get compile-time errors.
40 // For more detailed rules and regulations, see the accompanying documentation.
45 #include <security_utilities/alloc.h>
46 #include <security_utilities/memstreams.h>
47 #include <security_cdsa_utilities/cssmdata.h>
48 #include <security_utilities/debugging.h>
53 namespace DataWalkers
{
59 # define DEBUGWALK(who) secinfo("walkers", "walk " who " %s@%p (%ld)", \
60 Debug::typeName(addr).c_str(), addr, size)
62 # define DEBUGWALK(who) /* nothing */
67 // SizeWalker simply walks a structure and calculates how many bytes
68 // CopyWalker would use to make a flat copy. This is naturally at least
69 // the sum of all relevant sizes, but can be more due to alignment and
72 class SizeWalker
: public LowLevelMemoryUtilities::Writer::Counter
{
75 void operator () (T
&obj
, size_t size
= sizeof(T
)) { }
78 void operator () (T
*addr
, size_t size
= sizeof(T
))
79 { DEBUGWALK("size"); LowLevelMemoryUtilities::Writer::Counter::insert(size
); }
81 void blob(void *addr
, size_t size
)
82 { (*this)(addr
, size
); }
84 void reserve(size_t space
)
85 { LowLevelMemoryUtilities::Writer::Counter::insert(space
); }
87 static const bool needsRelinking
= false;
88 static const bool needsSize
= true;
93 // CopyWalker makes a deep, flat copy of a structure. The result will work
94 // just like the original (with all elements recursively copied), except that
95 // it occupies contiguous memory.
97 class CopyWalker
: public LowLevelMemoryUtilities::Writer
{
100 CopyWalker(void *base
) : LowLevelMemoryUtilities::Writer(base
) { }
104 void operator () (T
&obj
, size_t size
= sizeof(T
))
108 void operator () (T
* &addr
, size_t size
= sizeof(T
))
112 addr
= reinterpret_cast<T
*>(LowLevelMemoryUtilities::Writer::operator () (addr
, size
));
116 void blob(T
* &addr
, size_t size
)
117 { (*this)(addr
, size
); }
119 static const bool needsRelinking
= true;
120 static const bool needsSize
= true;
126 // Walk a structure and apply a constant linear shift to all pointers
127 // encountered. This is useful when a structure and its deep components
128 // have been linearly shifted by something (say, an IPC transit).
130 class ReconstituteWalker
{
132 ReconstituteWalker(off_t offset
) : mOffset(offset
) { }
133 ReconstituteWalker(void *ptr
, void *base
)
134 : mOffset(LowLevelMemoryUtilities::difference(ptr
, base
)) { }
137 void operator () (T
&obj
, size_t size
= sizeof(T
))
141 void operator () (T
* &addr
, size_t size
= 0)
143 DEBUGWALK("reconstitute");
145 addr
= LowLevelMemoryUtilities::increment
<T
>(addr
, (ptrdiff_t)mOffset
);
149 void blob(T
* &addr
, size_t size
)
150 { (*this)(addr
, size
); }
152 static const bool needsRelinking
= true;
153 static const bool needsSize
= false;
161 // Make an element-by-element copy of a structure. Each pointer followed
162 // uses a separate allocation for its pointed-to storage.
164 class ChunkCopyWalker
{
166 ChunkCopyWalker(Allocator
&alloc
= Allocator::standard()) : allocator(alloc
) { }
168 Allocator
&allocator
;
171 void operator () (T
&obj
, size_t size
= sizeof(T
))
175 void operator () (T
* &addr
, size_t size
= sizeof(T
))
177 DEBUGWALK("chunkcopy");
179 T
*copy
= reinterpret_cast<T
*>(allocator
.malloc(size
));
181 T
*copy
= allocator
.malloc
<T
>(size
);
183 memcpy(copy
, addr
, size
);
188 void blob(T
* &addr
, size_t size
)
189 { (*this)(addr
, size
); }
191 static const bool needsRelinking
= true;
192 static const bool needsSize
= true;
197 // Walk a structure and call an Allocator to separate free each node.
198 // This is safe for non-trees (i.e. shared subsidiary nodes); such will
199 // only be freed once.
201 class ChunkFreeWalker
{
203 ChunkFreeWalker(Allocator
&alloc
= Allocator::standard()) : allocator(alloc
) { }
205 Allocator
&allocator
;
208 void operator () (T
&obj
, size_t size
= 0)
212 void operator () (T
*addr
, size_t size
= 0)
214 DEBUGWALK("chunkfree");
215 freeSet
.insert(addr
);
218 void blob(void *addr
, size_t size
)
219 { (*this)(addr
, 0); }
222 ~ChunkFreeWalker() { free(); }
224 static const bool needsRelinking
= false;
225 static const bool needsSize
= false;
228 std::set
<void *> freeSet
;
233 // Stand-alone operations for a single structure web.
234 // These simply create, use, and discard their operator objects internally.
244 // Special version for const pointer's
246 size_t size(const T
*obj
)
247 { return size(const_cast<T
*>(obj
)); }
251 T
*copy(const T
*obj
, void *addr
)
256 walk(w
, const_cast<T
* &>(obj
));
257 return const_cast<T
*>(obj
);
261 T
*copy(const T
*obj
, Allocator
&alloc
, size_t size
)
265 return copy(obj
, alloc
.malloc(size
));
269 T
*copy(const T
*obj
, Allocator
&alloc
= Allocator::standard())
271 return obj
? copy(obj
, alloc
, size(obj
)) : NULL
;
276 void relocate(T
*obj
, T
*base
)
279 ReconstituteWalker
w(LowLevelMemoryUtilities::difference(obj
, base
));
286 // chunkCopy and chunkFree can take pointer and non-pointer arguments.
287 // Don't try to declare the T arguments const (overload resolution will
288 // mess you over if you try). Just take const and nonconst Ts and take
289 // the const away internally.
292 typename Nonconst
<T
>::Type
*chunkCopy(T
*obj
, Allocator
&alloc
= Allocator::standard())
295 ChunkCopyWalker
w(alloc
);
296 return walk(w
, unconst_ref_cast
<T
*>(obj
));
302 T
chunkCopy(T obj
, Allocator
&alloc
= Allocator::standard())
304 ChunkCopyWalker
w(alloc
);
310 void chunkFree(T
*obj
, Allocator
&alloc
= Allocator::standard())
313 ChunkFreeWalker
w(alloc
);
314 walk(w
, unconst_ref_cast
<T
*>(obj
));
319 void chunkFree(T
&obj
, Allocator
&alloc
= Allocator::standard())
321 ChunkFreeWalker
w(alloc
);
327 // Copier combines SizeWalker and CopyWalker into one operational package.
328 // this is useful if you need both the copy and its size (and don't want
329 // to re-run size()). Copier (like copy()) only applies to one object.
334 Copier(const T
*obj
, Allocator
&alloc
= Allocator::standard()) : allocator(alloc
)
340 mLength
= size(const_cast<T
*>(obj
));
342 mValue
= reinterpret_cast<T
*>(alloc
.malloc(mLength
));
344 mValue
= alloc
.malloc
<T
>(mLength
);
346 mValue
= copy(obj
, mValue
);
350 Copier(const T
*obj
, uint32 count
, Allocator
&alloc
= Allocator::standard())
358 sizer
.reserve(sizeof(T
) * count
); // initial vector size
359 for (uint32 n
= 0; n
< count
; n
++)
360 walk(sizer
, const_cast<T
&>(obj
[n
])); // dependent data sizes
363 mValue
= reinterpret_cast<T
*>(alloc
.malloc(mLength
));
365 mValue
= alloc
.malloc
<T
>(mLength
);
367 CopyWalker
copier(LowLevelMemoryUtilities::increment(mValue
, sizeof(T
) * count
));
368 for (uint32 n
= 0; n
< count
; n
++) {
370 walk(copier
, mValue
[n
]);
375 Allocator
&allocator
;
377 ~Copier() { allocator
.free(mValue
); }
379 T
*value() const { return mValue
; }
380 operator T
*() const { return value(); }
381 size_t length() const { return mLength
; }
383 T
*keep() { T
*result
= mValue
; mValue
= NULL
; return result
; }
391 } // end namespace DataWalkers
392 } // end namespace Security