le_safeRef.h

Go to the documentation of this file.
1 /**
2  * @page c_safeRef Safe References API
3  *
4  * @subpage le_safeRef.h "API Reference"
5  *
6  * <HR>
7  *
8  *
9  * The term "reference" is used to mean "opaque data that refers to some conceptual object".
10  * It is intentionally vague to support "information hiding". Behind the
11  * scenes, different implementations can use almost anything that fits into a pointer as a
12  * "reference". Often, they are indexes into arrays or actual pointers to memory objects.
13  * When passing those references through an API to outside clients, the implementation
14  * becomes exposed to crash bugs when clients
15  * pass those references back into the API damaged or stale ("stale" meaning
16  * something that has been deleted).
17  *
18  * <b> Safe References </b> are designed to help protect against damaged or stale references being
19  * used by clients.
20  *
21  * @section c_safeRef_create Create Safe Reference
22  *
23  * Client calls an API's "Create" function:
24  * - "Create" function creates an object.
25  * - "Create" function creates a "Safe Reference" for the new object @c le_ref_CreateRef()
26  * - "Create" function returns the Safe Reference.
27  *
28  * @section c_safeRef_lookup Lookup Pointer
29  *
30  * Followed by:
31  *
32  * Client calls another API function, passing in the Safe Reference:
33  * - API function translates the Safe Reference back into an object pointer @c le_ref_Lookup()
34  * - API function acts on the object.
35  *
36  * @section c_safeRef_delete Delete Safe Reference
37  *
38  * Finishing with:
39  *
40  * Client calls API's "Delete" function, passing in the Safe Reference:
41  * - "Delete" function translates the Safe Reference back into a pointer to its object.
42  * - "Delete" function invalidates the Safe Reference @c le_ref_DeleteRef()
43  * - "Delete" function deletes the object.
44  *
45  * At this point, if the Client calls an API function and passes that same (now invalid) Safe
46  * Reference (or if the client accidentally passes in some garbage value, like a pointer or zero),
47  * the API function will try to translate that into an object pointer. But it'll be told that it's
48  * an invalid Safe Reference. The API function can then handle it gracefully, rather
49  * than just acting as if it were a valid reference and clobbering the object's deallocated
50  * memory or some other object that's reusing the old object's memory.
51  *
52  * @section c_safeRef_map Create Reference Map
53  *
54  * A <b> Reference Map </b> object can be used to create Safe References and keep track of the
55  * mappings from Safe References to pointers. At start-up, a Reference Map can be created
56  * dynamically by calling @c le_ref_CreateMap(), or can be allocated statically at compile time
57  * via @c LE_REF_DEFINE_STATIC_MAP() and initialized via @c le_ref_InitStaticMap().
58  *
59  * @section c_safeRef_multithreading Multithreading
60  *
61  * This API's functions are reentrant, but not thread safe. If there's the slightest
62  * possibility the same Reference Map will be accessed by two threads at the same time, use
63  * a mutex or some other thread synchronization mechanism to protect the Reference Map from
64  * concurrent access.
65  *
66  * @section c_safeRef_example Sample Code
67  *
68  * Here's an API Definition sample:
69  *
70  * @code
71  * // Opaque reference to Foo objects.
72  * typedef struct xyz_foo_Obj* xyz_foo_ObjRef_t;
73  *
74  * xyz_foo_Ref_t xyz_foo_CreateObject
75  * (
76  * void
77  * );
78  *
79  * void xyz_foo_DoSomething
80  * (
81  * xyz_foo_Ref_t objRef
82  * );
83  *
84  * void xyz_foo_DeleteObject
85  * (
86  * xyz_foo_Ref_t objRef
87  * );
88  * @endcode
89  *
90  * Here's an API Implementation sample:
91  *
92  * @code
93  * // Maximum number of Foo objects we expect to have at one time.
94  * #define MAX_FOO_OBJECTS 27
95  *
96  * // Actual Foo objects.
97  * typedef struct
98  * {
99  * ...
100  * }
101  * Foo_t;
102  *
103  * // Pool from which Foo objects are allocated.
104  * le_mem_PoolRef_t FooPool;
105  *
106  * // Safe Reference Map for Foo objects.
107  * le_ref_MapRef_t FooRefMap;
108  *
109  * COMPONENT_INIT
110  * {
111  * // Create the Foo object pool.
112  * FooPool = le_mem_CreatePool("FooPool", sizeof(Foo_t));
113  * le_mem_ExpandPool(FooPool, MAX_FOO_OBJECTS);
114  *
115  * // Create the Safe Reference Map to use for Foo object Safe References.
116  * FooRefMap = le_ref_CreateMap("FooMap", MAX_FOO_OBJECTS);
117  * };
118  *
119  * xyz_foo_Ref_t xyz_foo_CreateObject
120  * (
121  * void
122  * )
123  * {
124  * Foo_t* fooPtr = le_mem_ForceAlloc(FooPool);
125  *
126  * // Initialize the new Foo object.
127  * ...
128  *
129  * // Create and return a Safe Reference for this Foo object.
130  * return le_ref_CreateRef(FooRefMap, fooPtr);
131  * }
132  *
133  * void xyz_foo_DoSomething
134  * (
135  * xyz_foo_Ref_t objRef
136  * )
137  * {
138  * Foo_t* fooPtr = le_ref_Lookup(FooRefMap, objRef);
139  *
140  * if (fooPtr == NULL)
141  * {
142  * LE_CRIT("Invalid reference (%p) provided!", objRef);
143  * return;
144  * }
145  *
146  * // Do something to the object.
147  * ...
148  * }
149  *
150  * void xyz_foo_DeleteObject
151  * (
152  * xyz_foo_Ref_t objRef
153  * )
154  * {
155  * Foo_t* fooPtr = le_ref_Lookup(FooRefMap, objRef);
156  *
157  * if (fooPtr == NULL)
158  * {
159  * LE_CRIT("Invalid reference (%p) provided!", objRef);
160  * return;
161  * }
162  *
163  * // Invalidate the Safe Reference.
164  * le_ref_DeleteRef(FooRefMap, objRef);
165  *
166  * // Release the Foo object.
167  * le_mem_Release(fooPtr);
168  * }
169  * @endcode
170  *
171  * <HR>
172  *
173  * Copyright (C) Sierra Wireless Inc.
174  */
175 
176 /** @file le_safeRef.h
177  *
178  * Legato @ref c_safeRef include file.
179  *
180  * Copyright (C) Sierra Wireless Inc.
181  */
182 
183 #ifndef LEGATO_SAFEREF_INCLUDE_GUARD
184 #define LEGATO_SAFEREF_INCLUDE_GUARD
185 
186 //--------------------------------------------------------------------------------------------------
187 /**
188  * Maximum string length and byte storage size of safe reference map names.
189  */
190 //--------------------------------------------------------------------------------------------------
191 #define LIMIT_MAX_SAFE_REF_NAME_LEN 31
192 #define LIMIT_MAX_SAFE_REF_NAME_BYTES (LIMIT_MAX_SAFE_REF_NAME_LEN + 1)
193 
194 
195 //--------------------------------------------------------------------------------------------------
196 /**
197  * Reference to a "Reference Map" object, which stores mappings from Safe References to pointers.
198  */
199 //--------------------------------------------------------------------------------------------------
200 typedef struct le_ref_Map *le_ref_MapRef_t;
201 
202 
203 //--------------------------------------------------------------------------------------------------
204 /**
205  * Reference to an "iterator" object, used to manage iterating a collection of safe refs.
206  */
207 //--------------------------------------------------------------------------------------------------
208 typedef struct le_ref_Iter *le_ref_IterRef_t;
209 
210 
211 //--------------------------------------------------------------------------------------------------
212 /**
213  * Internal block type.
214  */
215 //--------------------------------------------------------------------------------------------------
216 struct le_ref_Block;
217 
218 
219 // Internal block sizing
220 #define LE_REF_BLOCK_SIZE(numRefs) (1 + (numRefs))
221 
222 //--------------------------------------------------------------------------------------------------
223 /**
224  * Reference Map object, which stores mappings from Safe References to pointers.
225  *
226  * @note This should not be used directly.
227  */
228 //--------------------------------------------------------------------------------------------------
230 {
231  le_dls_Link_t entry; ///< Map list entry, for inspection tools.
232 
233 #if LE_CONFIG_SAFE_REF_NAMES_ENABLED
234  char name[LIMIT_MAX_SAFE_REF_NAME_BYTES]; ///< Descriptive name for debugging.
235  le_log_TraceRef_t traceRef; ///< Trace reference for debugging.
236 #endif
237 
238  size_t index; ///< Iterator.
239  bool advance; ///< Iterator advance flag.
240  size_t size; ///< Total allocated entries.
241  size_t maxRefs; ///< Nominal maximum number of safe references.
242  uint32_t mapBase; ///< Randomized "base" for references in this map.
243 
244  struct le_ref_Block *blocksPtr; ///< Block list head.
245 };
246 
247 //--------------------------------------------------------------------------------------------------
248 /**
249  * Declare variables for a static safe reference map.
250  *
251  * In a static safe reference map the space for the maximum number of references is allocated at
252  * compile time.
253  */
254 //--------------------------------------------------------------------------------------------------
255 #define LE_REF_DEFINE_STATIC_MAP(name, maxRefs) \
256  static struct le_ref_Map _ref_##name##Map; \
257  static void *_ref_##name##Data[LE_REF_BLOCK_SIZE(maxRefs)]
258 
259 /// @cond HIDDEN_IN_USER_DOCS
260 //--------------------------------------------------------------------------------------------------
261 /**
262  * Internal function used to implement le_ref_InitStaticMap().
263  */
264 //--------------------------------------------------------------------------------------------------
265 le_ref_MapRef_t _le_ref_InitStaticMap
266 (
267 #if LE_CONFIG_SAFE_REF_NAMES_ENABLED
268  const char *name,
269 #endif
270  size_t maxRefs,
271  le_ref_MapRef_t mapPtr,
272  void *data
273 );
274 /// @endcond
275 
276 //--------------------------------------------------------------------------------------------------
277 /**
278  * Initialize an already allocated Reference Map that can hold mappings from Safe References to
279  * pointers.
280  *
281  * @param[in] name Name of the map as specified in LE_REF_DEFINE_STATIC_MAP().
282  * @param[in] maxRefs Maximum number of Safe References expected to be kept in this Reference Map
283  * at any one time.
284  *
285  * @return The initialized reference map.
286  */
287 //--------------------------------------------------------------------------------------------------
288 #if LE_CONFIG_SAFE_REF_NAMES_ENABLED
289 # define le_ref_InitStaticMap(name, maxRefs) \
290  _le_ref_InitStaticMap(#name, (maxRefs), &_ref_##name##Map, _ref_##name##Data)
291 #else /* if not LE_CONFIG_SAFE_REF_NAMES_ENABLED */
292 # define le_ref_InitStaticMap(name, maxRefs) \
293  _le_ref_InitStaticMap((maxRefs), &_ref_##name##Map, _ref_##name##Data)
294 #endif /* end LE_CONFIG_SAFE_REF_NAMES_ENABLED */
295 
296 
297 #if LE_CONFIG_SAFE_REF_NAMES_ENABLED
298 //--------------------------------------------------------------------------------------------------
299 /**
300  * Create a Reference Map that can hold mappings from Safe References to pointers.
301  *
302  * @param[in] name Name of the map (for diagnostics).
303  * @param[in] maxRefs Maximum number of Safe References expected to be kept in this Reference Map
304  * at any one time.
305  *
306  * @return A reference to the Reference Map object.
307  */
308 //--------------------------------------------------------------------------------------------------
309 le_ref_MapRef_t le_ref_CreateMap
310 (
311  const char *name,
312  size_t maxRefs
313 );
314 #else /* if not LE_CONFIG_SAFE_REF_NAMES_ENABLED */
315 /// @cond HIDDEN_IN_USER_DOCS
316 //--------------------------------------------------------------------------------------------------
317 /**
318  * Internal function used to implement le_ref_CreateMap().
319  */
320 //--------------------------------------------------------------------------------------------------
321 le_ref_MapRef_t _le_ref_CreateMap(size_t maxRefs);
322 /// @endcond
323 //--------------------------------------------------------------------------------------------------
324 /**
325  * Create a Reference Map that can hold mappings from Safe References to pointers.
326  *
327  * @param[in] name Name of the map (for diagnostics).
328  * @param[in] maxRefs Maximum number of Safe References expected to be kept in this Reference Map
329  * at any one time.
330  *
331  * @return A reference to the Reference Map object.
332  */
333 //--------------------------------------------------------------------------------------------------
334 LE_DECLARE_INLINE le_ref_MapRef_t le_ref_CreateMap
335 (
336  const char *name,
337  size_t maxRefs
338 )
339 {
340  LE_UNUSED(name);
341  return _le_ref_CreateMap(maxRefs);
342 }
343 #endif /* end LE_CONFIG_SAFE_REF_NAMES_ENABLED */
344 
345 
346 //--------------------------------------------------------------------------------------------------
347 /**
348  * Creates a Safe Reference, storing a mapping between that reference and a specified pointer for
349  * future lookup.
350  *
351  * @return The Safe Reference.
352  */
353 //--------------------------------------------------------------------------------------------------
354 void* le_ref_CreateRef
355 (
356  le_ref_MapRef_t mapRef, ///< [in] Reference Map in which the mapping should be kept.
357  void* ptr ///< [in] Pointer value to which the new Safe Reference will be mapped.
358 );
359 
360 
361 //--------------------------------------------------------------------------------------------------
362 /**
363  * Translates a Safe Reference back to the pointer from when the Safe Reference
364  * was created.
365  *
366  * @return Pointer that the Safe Reference maps to, or NULL if the Safe Reference has been
367  * deleted or is invalid.
368  */
369 //--------------------------------------------------------------------------------------------------
370 void* le_ref_Lookup
371 (
372  le_ref_MapRef_t mapRef, ///< [in] Reference Map to do the lookup in.
373  void* safeRef ///< [in] Safe Reference to be translated into a pointer.
374 );
375 
376 
377 //--------------------------------------------------------------------------------------------------
378 /**
379  * Deletes a Safe Reference.
380  */
381 //--------------------------------------------------------------------------------------------------
382 void le_ref_DeleteRef
383 (
384  le_ref_MapRef_t mapRef, ///< [in] Reference Map to delete the mapping from.
385  void* safeRef ///< [in] Safe Reference to be deleted (invalidated).
386 );
387 
388 
389 //--------------------------------------------------------------------------------------------------
390 /**
391  * Gets an interator for step-by-step iteration over the map. In this mode the iteration is
392  * controlled by the calling function using the le_ref_NextNode() function. There is one iterator
393  * per map, and calling this function resets the iterator position to the start of the map. The
394  * iterator is not ready for data access until le_ref_NextNode() has been called at least once.
395  *
396  * @return Returns A reference to a hashmap iterator which is ready for le_hashmap_NextNode() to be
397  * called on it.
398  */
399 //--------------------------------------------------------------------------------------------------
401 (
402  le_ref_MapRef_t mapRef ///< [in] Reference to the map.
403 );
404 
405 
406 //--------------------------------------------------------------------------------------------------
407 /**
408  * Moves the iterator to the next key/value pair in the map.
409  *
410  * @return Returns LE_OK unless you go past the end of the map, then returns LE_NOT_FOUND.
411  * If the iterator has been invalidated by the map changing or you have previously
412  * received a LE_NOT_FOUND then this returns LE_FAULT.
413  */
414 //--------------------------------------------------------------------------------------------------
416 (
417  le_ref_IterRef_t iteratorRef ///< [IN] Reference to the iterator.
418 );
419 
420 
421 //--------------------------------------------------------------------------------------------------
422 /**
423  * Retrieves a pointer to the safe ref iterator is currently pointing at. If the iterator has just
424  * been initialized and le_hashmap_NextNode() has not been called, or if the iterator has been
425  * invalidated then this will return NULL.
426  *
427  * @return A pointer to the current key, or NULL if the iterator has been invalidated or is not
428  * ready.
429  *
430  */
431 //--------------------------------------------------------------------------------------------------
432 const void* le_ref_GetSafeRef
433 (
434  le_ref_IterRef_t iteratorRef ///< [IN] Reference to the iterator.
435 );
436 
437 
438 //--------------------------------------------------------------------------------------------------
439 /**
440  * Retrieves a pointer to the value which the iterator is currently pointing at. If the iterator
441  * has just been initialized and le_ref_NextNode() has not been called, or if the iterator has been
442  * invalidated then this will return NULL.
443  *
444  * @return A pointer to the current value, or NULL if the iterator has been invalidated or is not
445  * ready.
446  */
447 //--------------------------------------------------------------------------------------------------
448 void* le_ref_GetValue
449 (
450  le_ref_IterRef_t iteratorRef ///< [IN] Reference to the iterator.
451 );
452 
453 
454 //--------------------------------------------------------------------------------------------------
455 /**
456  * Immediately enables tracing on a particular safe reference map object.
457  **/
458 //--------------------------------------------------------------------------------------------------
460 (
461  le_ref_MapRef_t mapRef ///< [in] Reference to the map
462 );
463 
464 #endif // LEGATO_SAFEREF_INCLUDE_GUARD
le_log_TraceRef_t traceRef
Trace reference for debugging.
Definition: le_safeRef.h:235
uint32_t mapBase
Randomized "base" for references in this map.
Definition: le_safeRef.h:242
le_result_t le_ref_NextNode(le_ref_IterRef_t iteratorRef)
le_result_t
Definition: le_basics.h:45
char name[LIMIT_MAX_SAFE_REF_NAME_BYTES]
Descriptive name for debugging.
Definition: le_safeRef.h:234
#define LE_UNUSED(v)
Definition: le_basics.h:366
Definition: le_safeRef.h:229
size_t index
Iterator.
Definition: le_safeRef.h:238
struct le_ref_Block * blocksPtr
Block list head.
Definition: le_safeRef.h:244
const void * le_ref_GetSafeRef(le_ref_IterRef_t iteratorRef)
le_dls_Link_t entry
Map list entry, for inspection tools.
Definition: le_safeRef.h:231
bool advance
Iterator advance flag.
Definition: le_safeRef.h:239
size_t maxRefs
Nominal maximum number of safe references.
Definition: le_safeRef.h:241
size_t size
Total allocated entries.
Definition: le_safeRef.h:240
void * le_ref_Lookup(le_ref_MapRef_t mapRef, void *safeRef)
le_ref_IterRef_t le_ref_GetIterator(le_ref_MapRef_t mapRef)
void * le_ref_CreateRef(le_ref_MapRef_t mapRef, void *ptr)
void le_ref_EnableTrace(le_ref_MapRef_t mapRef)
le_ref_MapRef_t le_ref_CreateMap(const char *name, size_t maxRefs)
void * le_ref_GetValue(le_ref_IterRef_t iteratorRef)
struct le_ref_Iter * le_ref_IterRef_t
Definition: le_safeRef.h:208
void le_ref_DeleteRef(le_ref_MapRef_t mapRef, void *safeRef)
#define LE_DECLARE_INLINE
Definition: le_basics.h:317