]>
git.saurik.com Git - apple/security.git/blob - Security/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) secdebug("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;
125 // Walk a structure and apply a constant linear shift to all pointers
126 // encountered. This is useful when a structure and its deep components
127 // have been linearly shifted by something (say, an IPC transit).
129 class ReconstituteWalker
{
131 ReconstituteWalker(off_t offset
) : mOffset(offset
) { }
132 ReconstituteWalker(void *ptr
, void *base
)
133 : mOffset(LowLevelMemoryUtilities::difference(ptr
, base
)) { }
136 void operator () (T
&obj
, size_t size
= sizeof(T
))
140 void operator () (T
* &addr
, size_t size
= 0)
142 DEBUGWALK("reconstitute");
144 addr
= LowLevelMemoryUtilities::increment
<T
>(addr
, (ptrdiff_t)mOffset
);
148 void blob(T
* &addr
, size_t size
)
149 { (*this)(addr
, size
); }
151 static const bool needsRelinking
= true;
152 static const bool needsSize
= false;
160 // Make an element-by-element copy of a structure. Each pointer followed
161 // uses a separate allocation for its pointed-to storage.
163 class ChunkCopyWalker
{
165 ChunkCopyWalker(Allocator
&alloc
= Allocator::standard()) : allocator(alloc
) { }
167 Allocator
&allocator
;
170 void operator () (T
&obj
, size_t size
= sizeof(T
))
174 void operator () (T
* &addr
, size_t size
= sizeof(T
))
176 DEBUGWALK("chunkcopy");
178 T
*copy
= reinterpret_cast<T
*>(allocator
.malloc(size
));
180 T
*copy
= allocator
.malloc
<T
>(size
);
182 memcpy(copy
, addr
, size
);
187 void blob(T
* &addr
, size_t size
)
188 { (*this)(addr
, size
); }
190 static const bool needsRelinking
= true;
191 static const bool needsSize
= true;
196 // Walk a structure and call an Allocator to separate free each node.
197 // This is safe for non-trees (i.e. shared subsidiary nodes); such will
198 // only be freed once.
200 class ChunkFreeWalker
{
202 ChunkFreeWalker(Allocator
&alloc
= Allocator::standard()) : allocator(alloc
) { }
204 Allocator
&allocator
;
207 void operator () (T
&obj
, size_t size
= 0)
211 void operator () (T
*addr
, size_t size
= 0)
213 DEBUGWALK("chunkfree");
214 freeSet
.insert(addr
);
217 void blob(void *addr
, size_t size
)
218 { (*this)(addr
, 0); }
221 ~ChunkFreeWalker() { free(); }
223 static const bool needsRelinking
= false;
224 static const bool needsSize
= false;
227 std::set
<void *> freeSet
;
232 // Stand-alone operations for a single structure web.
233 // These simply create, use, and discard their operator objects internally.
243 // Special version for const pointer's
245 size_t size(const T
*obj
)
246 { return size(const_cast<T
*>(obj
)); }
250 T
*copy(const T
*obj
, void *addr
)
255 walk(w
, const_cast<T
* &>(obj
));
256 return const_cast<T
*>(obj
);
260 T
*copy(const T
*obj
, Allocator
&alloc
, size_t size
)
264 return copy(obj
, alloc
.malloc(size
));
268 T
*copy(const T
*obj
, Allocator
&alloc
= Allocator::standard())
270 return obj
? copy(obj
, alloc
, size(obj
)) : NULL
;
275 void relocate(T
*obj
, T
*base
)
278 ReconstituteWalker
w(LowLevelMemoryUtilities::difference(obj
, base
));
285 // chunkCopy and chunkFree can take pointer and non-pointer arguments.
286 // Don't try to declare the T arguments const (overload resolution will
287 // mess you over if you try). Just take const and nonconst Ts and take
288 // the const away internally.
291 typename Nonconst
<T
>::Type
*chunkCopy(T
*obj
, Allocator
&alloc
= Allocator::standard())
294 ChunkCopyWalker
w(alloc
);
295 return walk(w
, unconst_ref_cast
<T
*>(obj
));
301 T
chunkCopy(T obj
, Allocator
&alloc
= Allocator::standard())
303 ChunkCopyWalker
w(alloc
);
309 void chunkFree(T
*obj
, Allocator
&alloc
= Allocator::standard())
312 ChunkFreeWalker
w(alloc
);
313 walk(w
, unconst_ref_cast
<T
*>(obj
));
318 void chunkFree(const T
&obj
, Allocator
&alloc
= Allocator::standard())
320 ChunkFreeWalker
w(alloc
);
326 // Copier combines SizeWalker and CopyWalker into one operational package.
327 // this is useful if you need both the copy and its size (and don't want
328 // to re-run size()). Copier (like copy()) only applies to one object.
333 Copier(const T
*obj
, Allocator
&alloc
= Allocator::standard()) : allocator(alloc
)
339 mLength
= size(const_cast<T
*>(obj
));
341 mValue
= reinterpret_cast<T
*>(alloc
.malloc(mLength
));
343 mValue
= alloc
.malloc
<T
>(mLength
);
345 mValue
= copy(obj
, mValue
);
349 Copier(const T
*obj
, uint32 count
, Allocator
&alloc
= Allocator::standard())
357 sizer
.reserve(sizeof(T
) * count
); // initial vector size
358 for (uint32 n
= 0; n
< count
; n
++)
359 walk(sizer
, const_cast<T
&>(obj
[n
])); // dependent data sizes
362 mValue
= reinterpret_cast<T
*>(alloc
.malloc(mLength
));
364 mValue
= alloc
.malloc
<T
>(mLength
);
366 CopyWalker
copier(LowLevelMemoryUtilities::increment(mValue
, sizeof(T
) * count
));
367 for (uint32 n
= 0; n
< count
; n
++) {
369 walk(copier
, mValue
[n
]);
374 Allocator
&allocator
;
376 ~Copier() { allocator
.free(mValue
); }
378 T
*value() const { return mValue
; }
379 operator T
*() const { return value(); }
380 size_t length() const { return mLength
; }
382 T
*keep() { T
*result
= mValue
; mValue
= NULL
; return result
; }
390 } // end namespace DataWalkers
391 } // end namespace Security