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  (inline_static_assert( \
291  sizeof(_ref_##name##Data) == \
292  sizeof(void *[LE_REF_BLOCK_SIZE(maxRefs)]), \
293  "initial map size does not match definition"), \
294  _le_ref_InitStaticMap(#name, (maxRefs), &_ref_##name##Map, _ref_##name##Data))
295 #else /* if not LE_CONFIG_SAFE_REF_NAMES_ENABLED */
296 # define le_ref_InitStaticMap(name, maxRefs) \
297  _le_ref_InitStaticMap((maxRefs), &_ref_##name##Map, _ref_##name##Data)
298 #endif /* end LE_CONFIG_SAFE_REF_NAMES_ENABLED */
299 
300 
301 #if LE_CONFIG_SAFE_REF_NAMES_ENABLED
302 //--------------------------------------------------------------------------------------------------
303 /**
304  * Create a Reference Map that can hold mappings from Safe References to pointers.
305  *
306  * @param[in] name Name of the map (for diagnostics).
307  * @param[in] maxRefs Maximum number of Safe References expected to be kept in this Reference Map
308  * at any one time.
309  *
310  * @return A reference to the Reference Map object.
311  */
312 //--------------------------------------------------------------------------------------------------
313 le_ref_MapRef_t le_ref_CreateMap
314 (
315  const char *name,
316  size_t maxRefs
317 );
318 #else /* if not LE_CONFIG_SAFE_REF_NAMES_ENABLED */
319 /// @cond HIDDEN_IN_USER_DOCS
320 //--------------------------------------------------------------------------------------------------
321 /**
322  * Internal function used to implement le_ref_CreateMap().
323  */
324 //--------------------------------------------------------------------------------------------------
325 le_ref_MapRef_t _le_ref_CreateMap(size_t maxRefs);
326 /// @endcond
327 //--------------------------------------------------------------------------------------------------
328 /**
329  * Create a Reference Map that can hold mappings from Safe References to pointers.
330  *
331  * @param[in] name Name of the map (for diagnostics).
332  * @param[in] maxRefs Maximum number of Safe References expected to be kept in this Reference Map
333  * at any one time.
334  *
335  * @return A reference to the Reference Map object.
336  */
337 //--------------------------------------------------------------------------------------------------
338 LE_DECLARE_INLINE le_ref_MapRef_t le_ref_CreateMap
339 (
340  const char *name,
341  size_t maxRefs
342 )
343 {
344  LE_UNUSED(name);
345  return _le_ref_CreateMap(maxRefs);
346 }
347 #endif /* end LE_CONFIG_SAFE_REF_NAMES_ENABLED */
348 
349 
350 //--------------------------------------------------------------------------------------------------
351 /**
352  * Creates a Safe Reference, storing a mapping between that reference and a specified pointer for
353  * future lookup.
354  *
355  * @return The Safe Reference.
356  */
357 //--------------------------------------------------------------------------------------------------
358 void* le_ref_CreateRef
359 (
360  le_ref_MapRef_t mapRef, ///< [in] Reference Map in which the mapping should be kept.
361  void* ptr ///< [in] Pointer value to which the new Safe Reference will be mapped.
362 );
363 
364 
365 //--------------------------------------------------------------------------------------------------
366 /**
367  * Translates a Safe Reference back to the pointer from when the Safe Reference
368  * was created.
369  *
370  * @return Pointer that the Safe Reference maps to, or NULL if the Safe Reference has been
371  * deleted or is invalid.
372  */
373 //--------------------------------------------------------------------------------------------------
374 void* le_ref_Lookup
375 (
376  le_ref_MapRef_t mapRef, ///< [in] Reference Map to do the lookup in.
377  void* safeRef ///< [in] Safe Reference to be translated into a pointer.
378 );
379 
380 
381 //--------------------------------------------------------------------------------------------------
382 /**
383  * Deletes a Safe Reference.
384  */
385 //--------------------------------------------------------------------------------------------------
386 void le_ref_DeleteRef
387 (
388  le_ref_MapRef_t mapRef, ///< [in] Reference Map to delete the mapping from.
389  void* safeRef ///< [in] Safe Reference to be deleted (invalidated).
390 );
391 
392 
393 //--------------------------------------------------------------------------------------------------
394 /**
395  * Gets an interator for step-by-step iteration over the map. In this mode the iteration is
396  * controlled by the calling function using the le_ref_NextNode() function. There is one iterator
397  * per map, and calling this function resets the iterator position to the start of the map. The
398  * iterator is not ready for data access until le_ref_NextNode() has been called at least once.
399  *
400  * @return Returns A reference to a hashmap iterator which is ready for le_hashmap_NextNode() to be
401  * called on it.
402  */
403 //--------------------------------------------------------------------------------------------------
405 (
406  le_ref_MapRef_t mapRef ///< [in] Reference to the map.
407 );
408 
409 
410 //--------------------------------------------------------------------------------------------------
411 /**
412  * Moves the iterator to the next key/value pair in the map.
413  *
414  * @return Returns LE_OK unless you go past the end of the map, then returns LE_NOT_FOUND.
415  * If the iterator has been invalidated by the map changing or you have previously
416  * received a LE_NOT_FOUND then this returns LE_FAULT.
417  */
418 //--------------------------------------------------------------------------------------------------
420 (
421  le_ref_IterRef_t iteratorRef ///< [IN] Reference to the iterator.
422 );
423 
424 
425 //--------------------------------------------------------------------------------------------------
426 /**
427  * Retrieves a pointer to the safe ref iterator is currently pointing at. If the iterator has just
428  * been initialized and le_hashmap_NextNode() has not been called, or if the iterator has been
429  * invalidated then this will return NULL.
430  *
431  * @return A pointer to the current key, or NULL if the iterator has been invalidated or is not
432  * ready.
433  *
434  */
435 //--------------------------------------------------------------------------------------------------
436 const void* le_ref_GetSafeRef
437 (
438  le_ref_IterRef_t iteratorRef ///< [IN] Reference to the iterator.
439 );
440 
441 
442 //--------------------------------------------------------------------------------------------------
443 /**
444  * Retrieves a pointer to the value which the iterator is currently pointing at. If the iterator
445  * has just been initialized and le_ref_NextNode() has not been called, or if the iterator has been
446  * invalidated then this will return NULL.
447  *
448  * @return A pointer to the current value, or NULL if the iterator has been invalidated or is not
449  * ready.
450  */
451 //--------------------------------------------------------------------------------------------------
452 void* le_ref_GetValue
453 (
454  le_ref_IterRef_t iteratorRef ///< [IN] Reference to the iterator.
455 );
456 
457 
458 //--------------------------------------------------------------------------------------------------
459 /**
460  * Immediately enables tracing on a particular safe reference map object.
461  **/
462 //--------------------------------------------------------------------------------------------------
464 (
465  le_ref_MapRef_t mapRef ///< [in] Reference to the map
466 );
467 
468 #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:46
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:369
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:320