@@ -140,6 +140,8 @@ typedef struct H5B_ins_ud_t {
140140/********************/
141141/* Local Prototypes */
142142/********************/
143+ static herr_t H5B_find_helper (H5F_t * f , const H5B_class_t * type , haddr_t addr , int exp_level , bool * found ,
144+ void * udata );
143145static H5B_ins_t H5B__insert_helper (H5F_t * f , H5B_ins_ud_t * bt_ud , const H5B_class_t * type , uint8_t * lt_key ,
144146 bool * lt_key_changed , uint8_t * md_key , void * udata , uint8_t * rt_key ,
145147 bool * rt_key_changed , H5B_ins_ud_t * split_bt_ud /*out*/ );
@@ -255,26 +257,67 @@ H5B_create(H5F_t *f, const H5B_class_t *type, void *udata, haddr_t *addr_p /*out
255257} /* end H5B_create() */
256258
257259/*-------------------------------------------------------------------------
258- * Function: H5B_find
260+ * Function: H5B_find
259261 *
260- * Purpose: Locate the specified information in a B-tree and return
261- * that information by filling in fields of the caller-supplied
262- * UDATA pointer depending on the type of leaf node
263- * requested. The UDATA can point to additional data passed
264- * to the key comparison function.
262+ * Purpose: Locate the specified information in a B-tree and return
263+ * that information by filling in fields of the
264+ * caller-supplied UDATA pointer depending on the type of leaf
265+ * node requested. The UDATA can point to additional data
266+ * passed to the key comparison function.
265267 *
266- * Note: This function does not follow the left/right sibling
267- * pointers since it assumes that all nodes can be reached
268- * from the parent node.
268+ * Note: This function does not follow the left/right sibling
269+ * pointers since it assumes that all nodes can be reached
270+ * from the parent node.
269271 *
270- * Return: Non-negative (true/false) on success (if found, values returned
271- * through the UDATA argument). Negative on failure (if not found,
272- * UDATA is undefined).
272+ * Return: Non-negative (true/false) on success (if found, values
273+ * returned through the UDATA argument). Negative on failure
274+ * (if not found, UDATA is undefined).
273275 *
274276 *-------------------------------------------------------------------------
275277 */
276278herr_t
277279H5B_find (H5F_t * f , const H5B_class_t * type , haddr_t addr , bool * found , void * udata )
280+ {
281+ herr_t ret_value = SUCCEED ;
282+
283+ FUNC_ENTER_NOAPI (FAIL )
284+
285+ /*
286+ * Check arguments.
287+ */
288+ assert (f );
289+ assert (type );
290+ assert (type -> decode );
291+ assert (type -> cmp3 );
292+ assert (type -> found );
293+ assert (H5_addr_defined (addr ));
294+
295+ if ((ret_value = H5B_find_helper (f , type , addr , H5B_UNKNOWN_NODELEVEL , found , udata )) < 0 )
296+ HGOTO_ERROR (H5E_BTREE , H5E_NOTFOUND , FAIL , "can't lookup key" );
297+
298+ done :
299+ FUNC_LEAVE_NOAPI (ret_value )
300+ } /* end H5B_find() */
301+
302+ /*-------------------------------------------------------------------------
303+ * Function: H5B_find_helper
304+ *
305+ * Purpose: Recursive helper routine for H5B_find used to track node
306+ * levels and attempt to detect B-tree corruption during
307+ * lookups.
308+ *
309+ * Note: This function does not follow the left/right sibling
310+ * pointers since it assumes that all nodes can be reached
311+ * from the parent node.
312+ *
313+ * Return: Non-negative on success (if found, values returned through
314+ * the UDATA argument). Negative on failure (if not found,
315+ * UDATA is undefined).
316+ *
317+ *-------------------------------------------------------------------------
318+ */
319+ static herr_t
320+ H5B_find_helper (H5F_t * f , const H5B_class_t * type , haddr_t addr , int exp_level , bool * found , void * udata )
278321{
279322 H5B_t * bt = NULL ;
280323 H5UC_t * rc_shared ; /* Ref-counted shared info */
@@ -309,7 +352,7 @@ H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *uda
309352 cache_udata .f = f ;
310353 cache_udata .type = type ;
311354 cache_udata .rc_shared = rc_shared ;
312- cache_udata .exp_level = H5B_UNKNOWN_NODELEVEL ;
355+ cache_udata .exp_level = exp_level ;
313356 if (NULL == (bt = (H5B_t * )H5AC_protect (f , H5AC_BT , addr , & cache_udata , H5AC__READ_ONLY_FLAG )))
314357 HGOTO_ERROR (H5E_BTREE , H5E_CANTPROTECT , FAIL , "unable to load B-tree node" );
315358
@@ -333,7 +376,17 @@ H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *uda
333376 assert (idx < bt -> nchildren );
334377
335378 if (bt -> level > 0 ) {
336- if ((ret_value = H5B_find (f , type , bt -> child [idx ], found , udata )) < 0 )
379+ /* Sanity check to catch the case where the current node points to
380+ * itself and the current node was loaded with an expected node level
381+ * of H5B_UNKNOWN_NODELEVEL, thus bypassing the expected node level
382+ * check during deserialization and in the future if the node was
383+ * cached.
384+ */
385+ if (bt -> child [idx ] == addr )
386+ HGOTO_ERROR (H5E_BTREE , H5E_BADVALUE , FAIL , "cyclic B-tree detected" );
387+
388+ if ((ret_value = H5B_find_helper (f , type , bt -> child [idx ], (int )(bt -> level - 1 ), found , udata )) <
389+ 0 )
337390 HGOTO_ERROR (H5E_BTREE , H5E_NOTFOUND , FAIL , "can't lookup key in subtree" );
338391 } /* end if */
339392 else {
@@ -347,7 +400,7 @@ H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *uda
347400 HDONE_ERROR (H5E_BTREE , H5E_CANTUNPROTECT , FAIL , "unable to release node" );
348401
349402 FUNC_LEAVE_NOAPI (ret_value )
350- } /* end H5B_find () */
403+ } /* end H5B_find_helper () */
351404
352405/*-------------------------------------------------------------------------
353406 * Function: H5B__split
0 commit comments