From c31c819e3f3d908d9fccd61a777b006eccbdfb8e Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@redhat.com>
Date: Wed, 14 May 2014 16:41:30 -0700
Subject: [PATCH] Ticket #47780 - Some VLV search request causes memory leaks

Fix description:
. Modified idl_free interface as follows so that passed idl is cleared
  with NULL once the IDList is successfully freed.
    -idl_free(IDList *idl)
    +idl_free(IDList **idl)
  This change is used to clean up search candidates when ldbm_back_
  search_cleanup (ldbm_search.c) is called as an error return.  The
  cleanup function frees the search candidates when it's not NULL and
  it's not assigned to sr_candidates field in the search result. This
  fixes a memory leak when VLV/Sort op fails.
. ldbm_back_search_cleanup (ldbm_search.c) calls slapi_send_ldap_result
  if an ldap error is passed to the function.  The logic used to be
  "if (ldap_result>=LDAP_SUCCESS)", which is based upon that mozldap
  return codes are all positive.  Supporting openldap library, there
  is a chance to get a negative return code (e.g. LDAP_PARAM_ERROR ==
  -9).  This patch supports the negative return codes, as well.
. In ldbm_back_search (ldbm_search.c) vlv_filter_candidates could
  ruturn errors such as and LDAP_TIMELIMIT_EXCEEDED, LDAP_ADMINLIMIT_
  EXCEEDED.  The search results are supposed to be returned to the
  client with the error code if the control is not critical.  The code
  is added.
. The VLV operation stores the result in vlv_response_control.result
  in ldbm_back_search (ldbm_search.c), which occurs at 3 places, vlv_
  filter_candidates, sort_candidates and vlv_trim_candidates_txn.
  The return code from the latter calls used to override the former
  return code.  This patch fixes it to respect the former return code.
---
 ldap/servers/slapd/back-ldbm/ancestorid.c      |  28 ++---
 ldap/servers/slapd/back-ldbm/filterindex.c     |  34 ++---
 ldap/servers/slapd/back-ldbm/idl.c             |  92 +++++++-------
 ldap/servers/slapd/back-ldbm/idl_common.c      |  12 +-
 ldap/servers/slapd/back-ldbm/idl_new.c         |  20 +--
 ldap/servers/slapd/back-ldbm/import-merge.c    |   6 +-
 ldap/servers/slapd/back-ldbm/import-threads.c  |   4 +-
 ldap/servers/slapd/back-ldbm/index.c           |  16 +--
 ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c   |   2 +-
 ldap/servers/slapd/back-ldbm/ldbm_modrdn.c     |   4 +-
 ldap/servers/slapd/back-ldbm/ldbm_search.c     | 166 +++++++++++++++----------
 ldap/servers/slapd/back-ldbm/ldif2ldbm.c       |  23 ++--
 ldap/servers/slapd/back-ldbm/proto-back-ldbm.h |   2 +-
 ldap/servers/slapd/back-ldbm/seq.c             |   4 +-
 ldap/servers/slapd/back-ldbm/vlv.c             |   2 +-
 15 files changed, 220 insertions(+), 195 deletions(-)

diff --git a/ldap/servers/slapd/back-ldbm/ancestorid.c b/ldap/servers/slapd/back-ldbm/ancestorid.c
index b4d8292..8968549 100644
--- a/ldap/servers/slapd/back-ldbm/ancestorid.c
+++ b/ldap/servers/slapd/back-ldbm/ancestorid.c
@@ -152,7 +152,7 @@ static int ldbm_get_nonleaf_ids(backend *be, DB_TXN *txn, IDList **idl, ImportJo
         LDAPDebug(LDAP_DEBUG_TRACE, "found %lu nodes for ancestorid\n", 
                   (u_long)IDL_NIDS(nodes), 0, 0);
     } else {
-        idl_free(nodes);
+        idl_free(&nodes);
         *idl = NULL;
     }
 
@@ -295,7 +295,7 @@ static int ldbm_ancestorid_default_create_index(backend *be, ImportJob *job)
         /* Insert into ancestorid for this node */
         if (id2idl_hash_lookup(ht, &id, &ididl)) {
             descendants = idl_union_allids(be, ai_aid, ididl->idl, children);
-            idl_free(children);
+            idl_free(&children);
             if (id2idl_hash_remove(ht, &id) == 0) {
                 LDAPDebug(LDAP_DEBUG_ANY, "ancestorid hash_remove failed\n", 0,0,0);
             } else {
@@ -310,21 +310,21 @@ static int ldbm_ancestorid_default_create_index(backend *be, ImportJob *job)
         /* Get parentid for this entry */
         ret = ldbm_parentid(be, txn, id, &parentid);
         if (ret != 0) {
-            idl_free(descendants);
+            idl_free(&descendants);
             break;
         }
 
         /* A suffix entry does not have a parent */
         if (parentid == NOID) {
-            idl_free(descendants);
+            idl_free(&descendants);
             continue;
         }
 
         /* Insert into ancestorid for this node's parent */
         if (id2idl_hash_lookup(ht, &parentid, &ididl)) {
             IDList *idl = idl_union_allids(be, ai_aid, ididl->idl, descendants);
-            idl_free(descendants);
-            idl_free(ididl->idl);
+            idl_free(&descendants);
+            idl_free(&(ididl->idl));
             ididl->idl = idl;
         } else {
             ididl = (id2idl*)slapi_ch_calloc(1,sizeof(id2idl));
@@ -350,7 +350,7 @@ static int ldbm_ancestorid_default_create_index(backend *be, ImportJob *job)
     id2idl_hash_destroy(ht);
 
     /* Free any leftover idlists */
-    idl_free(nodes);
+    idl_free(&nodes);
 
     /* Release the parentid file */
     if (db_pid != NULL) {
@@ -503,7 +503,7 @@ static int ldbm_ancestorid_new_idl_create_index(backend *be, ImportJob *job)
         /* Insert into ancestorid for this node */
         ret = idl_store_block(be, db_aid, &key, children, txn, ai_aid);
         if (ret != 0) {
-            idl_free(children);
+            idl_free(&children);
             break;
         }
 
@@ -514,13 +514,13 @@ static int ldbm_ancestorid_new_idl_create_index(backend *be, ImportJob *job)
                 slapi_log_error(SLAPI_LOG_FATAL, sourcefile,
                                 "Error: ldbm_parentid on node index [" ID_FMT "] of [" ID_FMT "]\n",
                                 nids, nodes->b_nids);
-                idl_free(children);
+                idl_free(&children);
                 goto out;
             }
     
             /* A suffix entry does not have a parent */
             if (parentid == NOID) {
-                idl_free(children);
+                idl_free(&children);
                 break;
             }
     
@@ -532,7 +532,7 @@ static int ldbm_ancestorid_new_idl_create_index(backend *be, ImportJob *job)
             /* Insert into ancestorid for this node's parent */
             ret = idl_store_block(be, db_aid, &key, children, txn, ai_aid);
             if (ret != 0) {
-                idl_free(children);
+                idl_free(&children);
                 goto out;
             }
             id = parentid;
@@ -556,7 +556,7 @@ static int ldbm_ancestorid_new_idl_create_index(backend *be, ImportJob *job)
     }
 
     /* Free any leftover idlists */
-    idl_free(nodes);
+    idl_free(&nodes);
 
     /* Release the parentid file */
     if (db_pid != NULL) {
@@ -635,7 +635,7 @@ static int ldbm_parentid(backend *be, DB_TXN *txn, ID id, ID *ppid)
 
 static void id2idl_free(id2idl **ididl)
 {
-    idl_free((*ididl)->idl);
+    idl_free(&((*ididl)->idl));
     slapi_ch_free((void**)ididl);
 }
 
@@ -837,7 +837,7 @@ static int ldbm_ancestorid_index_update(
                 break;
             }
             node_id = idl_firstid(idl);
-            idl_free(idl);
+            idl_free(&idl);
         }
 
         /* Update ancestorid for the base entry */
diff --git a/ldap/servers/slapd/back-ldbm/filterindex.c b/ldap/servers/slapd/back-ldbm/filterindex.c
index 9ad2ab4..c8c40c4 100644
--- a/ldap/servers/slapd/back-ldbm/filterindex.c
+++ b/ldap/servers/slapd/back-ldbm/filterindex.c
@@ -399,7 +399,7 @@ presence_candidates(
         LDAPDebug(LDAP_DEBUG_TRACE, 
                       "fallback to eq index as pres index gave allids\n", 
                       0, 0, 0);
-        idl_free(idl);
+        idl_free(&idl);
         idl = index_range_read_ext(pb, be, type, indextype_EQUALITY,
                                    SLAPI_OP_GREATER_OR_EQUAL,
                                    NULL, NULL, 0, &txn, err, allidslimit);
@@ -481,7 +481,7 @@ extensible_candidates(
                     else if (keys == NULL || keys[0] == NULL)
                     {
                         /* no keys */
-                        idl_free (idl);
+                        idl_free (&idl);
                         idl = idl_allids (be);
                     }
                     else
@@ -516,8 +516,8 @@ extensible_candidates(
                             else
                             {
                                 IDList* tmp = idl_intersection (be, idl2, idl3);
-                                idl_free (idl2);
-                                idl_free (idl3);
+                                idl_free (&idl2);
+                                idl_free (&idl3);
                                 idl2 = tmp;
                             }
                             if (idl2 == NULL) break; /* look no further */
@@ -529,8 +529,8 @@ extensible_candidates(
                         else if (idl2 != NULL)
                         {
                             IDList* tmp = idl_union (be, idl, idl2);
-                            idl_free (idl);
-                            idl_free (idl2);
+                            idl_free (&idl);
+                            idl_free (&idl2);
                             idl = tmp;
                         }
                     }
@@ -828,7 +828,7 @@ list_candidates(
                 {
                     LDAPDebug( LDAP_DEBUG_TRACE,
                         "<= list_candidates NULL\n", 0, 0, 0 );
-                    idl_free( idl );
+                    idl_free( &idl );
                     idl = NULL;
                     goto out;
                 }
@@ -838,7 +838,7 @@ list_candidates(
                 == NULL && ftype == LDAP_FILTER_AND ) {
                     LDAPDebug( LDAP_DEBUG_TRACE,
                         "<= list_candidates NULL\n", 0, 0, 0 );
-                    idl_free( idl );
+                    idl_free( &idl );
                     idl = NULL;
                     goto out;
             }
@@ -862,15 +862,15 @@ list_candidates(
                     int notin_result = 0;
                     notin_result = idl_notin( be, idl, tmp, &new_idl );
                     if (notin_result) {
-                        idl_free(idl);
+                        idl_free(&idl);
                         idl = new_idl;
                     }
                 }
             } else {
                 idl = idl_intersection(be, idl, tmp);
-                idl_free( tmp2 );
+                idl_free( &tmp2 );
             }
-            idl_free( tmp );
+            idl_free( &tmp );
             /* stop if the list has gotten too small */
             if ((idl == NULL) ||
                 (idl_length(idl) <= FILTER_TEST_THRESHOLD))
@@ -880,8 +880,8 @@ list_candidates(
             slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
 
             idl = idl_union( be, idl, tmp );
-            idl_free( tmp );
-            idl_free( tmp2 );
+            idl_free( &tmp );
+            idl_free( &tmp2 );
             /* stop if we're already committed to an exhaustive
              * search. :(
              */
@@ -890,7 +890,7 @@ list_candidates(
             if (op_is_pagedresults(operation)) {
                 int nids = IDL_NIDS(idl);
                 if ( allidslimit > 0 && nids > allidslimit ) {
-                    idl_free( idl );
+                    idl_free( &idl );
                     idl = idl_allids( be );
                 }
             }
@@ -1013,7 +1013,7 @@ keys2idl(
         }
 #endif
         if ( idl2 == NULL ) {
-            idl_free( idl );
+            idl_free( &idl );
             idl = NULL;
             break;
         }
@@ -1025,8 +1025,8 @@ keys2idl(
 
             tmp = idl;
             idl = idl_intersection(be, idl, idl2);
-            idl_free( idl2 );
-            idl_free( tmp );
+            idl_free( &idl2 );
+            idl_free( &tmp );
             if ( idl == NULL ) {
                 break;
             }
diff --git a/ldap/servers/slapd/back-ldbm/idl.c b/ldap/servers/slapd/back-ldbm/idl.c
index a0bc139..6a7c7b0 100644
--- a/ldap/servers/slapd/back-ldbm/idl.c
+++ b/ldap/servers/slapd/back-ldbm/idl.c
@@ -284,12 +284,12 @@ idl_old_fetch(
 	if ( ! INDIRECT_BLOCK( idl ) ) {
 		/* make sure we have the current value of highest id */
 		if ( ALLIDS(idl) ) {
-			idl_free( idl );
+			idl_free( &idl );
 			idl = idl_allids( be );
 		}	
 		return( idl );
 	}
-       	idl_free( idl );
+       	idl_free( &idl );
 
 	/* Taking a transaction is expensive; so we try and optimize for the common case by not
 	   taking one above. If we have a indirect block; we need to take a transaction and re-read
@@ -311,7 +311,7 @@ idl_old_fetch(
 		dblayer_read_txn_commit(be, &s_txn);
 		/* make sure we have the current value of highest id */
 		if ( ALLIDS(idl) ) {
-			idl_free( idl );
+			idl_free( &idl );
 			idl = idl_allids( be );
 		}	
 		return( idl );
@@ -371,7 +371,7 @@ idl_old_fetch(
 	dblayer_read_txn_commit(be, &s_txn);	
 	tmp[i] = NULL;
 	slapi_ch_free((void**)&kstr );
-	idl_free( idl );
+	idl_free( &idl );
 
 	/* allocate space for the big block */
 	idl = idl_alloc( nids );
@@ -388,7 +388,7 @@ idl_old_fetch(
 		    tmp[i]->b_nids * sizeof(ID) );
 		nids += tmp[i]->b_nids;
 
-		idl_free( tmp[i] );
+		idl_free( &tmp[i] );
 	}
 	slapi_ch_free((void**)&tmp );
 
@@ -633,7 +633,7 @@ idl_old_insert_key(
 				   rc, (msg = dblayer_strerror( rc )) ? msg : "", 0 );
 		}
 
-		idl_free( idl );
+		idl_free( &idl );
 		idl_unlock_list(a->ai_idl,key);
 		return( rc );
 	}
@@ -659,10 +659,10 @@ idl_old_insert_key(
 		case 3:		/* id not inserted - block must be split */
 			/* check threshold for marking this an all-id block */
 			if ( a->ai_idl->idl_maxindirect < 2 ) {
-				idl_free( idl );
+				idl_free( &idl );
 				idl = idl_allids( be );
 				rc = idl_store( be, db, key, idl, txn );
-				idl_free( idl );
+				idl_free( &idl );
 
 				idl_unlock_list(a->ai_idl,key);
 				if ( rc != 0 && rc != DB_LOCK_DEADLOCK)
@@ -677,7 +677,7 @@ idl_old_insert_key(
 			}
 
 			idl_split_block( idl, id, &tmp, &tmp2 );
-			idl_free( idl );
+			idl_free( &idl );
 
 			/* create the header indirect block */
 			idl = idl_alloc( 3 );
@@ -690,9 +690,9 @@ idl_old_insert_key(
 			/* store it */
 			rc = idl_store( be, db, key, idl, txn );
 			if ( rc != 0 ) {
-				idl_free( idl );
-				idl_free( tmp );
-				idl_free( tmp2 );
+				idl_free( &idl );
+				idl_free( &tmp );
+				idl_free( &tmp2 );
 				if ( rc != DB_LOCK_DEADLOCK )
 				{
 					LDAPDebug( LDAP_DEBUG_ANY, "idl_insert_key 3 BAD %d %s\n",
@@ -716,9 +716,9 @@ idl_old_insert_key(
 			k2.dsize = strlen( kstr ) + 1;
 			rc = idl_store( be, db, &k2, tmp2, txn );
 			if ( rc != 0 ) {
-				idl_free( idl );
-				idl_free( tmp );
-				idl_free( tmp2 );
+				idl_free( &idl );
+				idl_free( &tmp );
+				idl_free( &tmp2 );
 				if ( rc != DB_LOCK_DEADLOCK )
 				{
 					LDAPDebug( LDAP_DEBUG_ANY, "idl_insert_key 4 BAD %d %s\n",
@@ -730,12 +730,12 @@ idl_old_insert_key(
 					    "idl_insert_key", "split", key, id);
 
 			slapi_ch_free((void**)&kstr );
-			idl_free( tmp );
-			idl_free( tmp2 );
+			idl_free( &tmp );
+			idl_free( &tmp2 );
 			break;
 		}
 
-		idl_free( idl );
+		idl_free( &idl );
 		idl_unlock_list(a->ai_idl,key);
 		if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
 		{
@@ -763,7 +763,7 @@ idl_old_insert_key(
 		    (u_long)id, key.dptr, i);
 #endif
 		idl_unlock_list(a->ai_idl,key);
-		idl_free( idl );
+		idl_free( &idl );
 		return( 0 );
 	}
 	if ( i != 0 ) {
@@ -787,7 +787,7 @@ idl_old_insert_key(
 		LDAPDebug( LDAP_DEBUG_ANY,
 		    "nonexistent continuation block (%s)\n", k2.dptr, 0, 0 );
 		idl_unlock_list(a->ai_idl,key);
-		idl_free( idl );
+		idl_free( &idl );
 		slapi_ch_free((void**)&kstr );
 		return( -1 );
 	}
@@ -915,9 +915,9 @@ idl_old_insert_key(
 
 				slapi_ch_free( (void **)&(k2.dptr) );
 				slapi_ch_free( (void **)&(k3.dptr) );
-				idl_free( tmp );
-				idl_free( tmp2 );
-				idl_free( idl );
+				idl_free( &tmp );
+				idl_free( &tmp2 );
+				idl_free( &idl );
 				idl_unlock_list(a->ai_idl,key);
 				return( rc );
 
@@ -945,7 +945,7 @@ idl_old_insert_key(
                                  * which is not correct.
                                  */
                                 rc = 0;
-				idl_free( tmp2 );
+				idl_free( &tmp2 );
 				break;
 			}
 			if ( rc != 0 ) {
@@ -990,7 +990,7 @@ idl_old_insert_key(
 
 			/* store allid block in place of header block */
 			if ( 0 == rc ) {
-				idl_free( idl );
+				idl_free( &idl );
 				idl = idl_allids( be );
 				rc = idl_store( be, db, key, idl, txn );
 				if (NULL != disposition) {
@@ -1000,14 +1000,14 @@ idl_old_insert_key(
 
 			slapi_ch_free( (void **)&(k2.dptr) );
 			slapi_ch_free( (void **)&(k3.dptr) );
-			idl_free( idl );
-			idl_free( tmp );
+			idl_free( &idl );
+			idl_free( &tmp );
 			idl_unlock_list(a->ai_idl,key);
 			return( rc );
 		}
 
 		idl_split_block( tmp, id, &tmp2, &tmp3 );
-		idl_free( tmp );
+		idl_free( &tmp );
 
 		/* create a new updated indirect header block */
 		tmp = idl_alloc( idl->b_nmax + 1 );
@@ -1025,8 +1025,8 @@ idl_old_insert_key(
 		/* store the header block */
 		rc = idl_store( be, db, key, tmp, txn );
 		if ( rc != 0 ) {
-			idl_free( tmp2 );
-			idl_free( tmp3 );
+			idl_free( &tmp2 );
+			idl_free( &tmp3 );
 			break;
 		}
 
@@ -1037,8 +1037,8 @@ idl_old_insert_key(
 		k2.dsize = strlen( kstr ) + 1;
 		rc = idl_store( be, db, &k2, tmp2, txn );
 		if ( rc != 0 ) {
-			idl_free( tmp2 );
-			idl_free( tmp3 );
+			idl_free( &tmp2 );
+			idl_free( &tmp3 );
 			break;
 		}
 
@@ -1049,22 +1049,22 @@ idl_old_insert_key(
 		k2.dsize = strlen( kstr ) + 1;
 		rc = idl_store( be, db, &k2, tmp3, txn );
 		if ( rc != 0 ) {
-			idl_free( tmp2 );
-			idl_free( tmp3 );
+			idl_free( &tmp2 );
+			idl_free( &tmp3 );
 			break;
 		}
 
 		idl_check_indirect (tmp, i, tmp2, tmp3,
 				    "idl_insert_key", "indirect split", key, id);
-		idl_free( tmp2 );
-		idl_free( tmp3 );
+		idl_free( &tmp2 );
+		idl_free( &tmp3 );
 		break;
 	}
 
 	slapi_ch_free( (void **)&(k2.dptr) );
 	slapi_ch_free( (void **)&(k3.dptr) );
-	idl_free( tmp );
-	idl_free( idl );
+	idl_free( &tmp );
+	idl_free( &idl );
 	idl_unlock_list(a->ai_idl,key);
 	return( rc );
 }
@@ -1100,7 +1100,7 @@ int idl_old_store_block(
 			/* If so, store an ALLIDS block */
 			IDList *all = idl_allids(be);
 			ret = idl_store(be,db,key,all,txn);
-			idl_free(all);
+			idl_free(&all);
 		} else {
 			/* Then , is it a block which is smaller than the size at which it needs splitting ? */
 			if (idl->b_nids <= (ID)priv->idl_maxids) {
@@ -1159,7 +1159,7 @@ int idl_old_store_block(
 					make_cont_key(&cont_key,key,lead_id);
 					/* Now store the continuation block */
 					ret = idl_store(be,db,&cont_key,this_cont_block,txn);
-					idl_free(this_cont_block);
+					idl_free(&this_cont_block);
 					slapi_ch_free(&(cont_key.data));
 					if ( ret != 0 && ret != DB_LOCK_DEADLOCK )
 					{
@@ -1181,7 +1181,7 @@ int idl_old_store_block(
 	}
 done:
 	/* Free master block */
-	idl_free(master_block);
+	idl_free(&master_block);
 	return ret;
 }
 
@@ -1442,7 +1442,7 @@ idl_old_delete_key(
 			break;
 		}
 
-		idl_free( idl );
+		idl_free( &idl );
 		idl_unlock_list(a->ai_idl,key);
 		LDAPDebug( LDAP_DEBUG_TRACE, "<= idl_delete_key(%s,%lu) %d (not indirect)\n",
 			   key->dptr, (u_long)id, rc );
@@ -1463,7 +1463,7 @@ idl_old_delete_key(
 	}
 	/* id smaller than smallest id - not there */
 	if ( i == 0 && id < idl->b_ids[i] ) {
-		idl_free( idl );
+		idl_free( &idl );
 		idl_unlock_list(a->ai_idl,key);
 		LDAPDebug( LDAP_DEBUG_TRACE, "<= idl_delete_key(%s,%lu) -666 (id not found)\n",
 			   key->dptr, (u_long)id, 0 );
@@ -1476,7 +1476,7 @@ idl_old_delete_key(
 	/* get the block to delete from */
 	make_cont_key( &contkey, key, idl->b_ids[i] );
 	if ( (didl = idl_fetch_one( li, db, &contkey, txn, &rc )) == NULL ) {
-		idl_free( idl );
+		idl_free( &idl );
 		idl_unlock_list(a->ai_idl,key);
 		if ( rc != DB_LOCK_DEADLOCK )
 		{
@@ -1563,8 +1563,8 @@ idl_old_delete_key(
 		rc = 0;
 		break;
 	}
-	idl_free( idl );
-	idl_free( didl );
+	idl_free( &idl );
+	idl_free( &didl );
 	slapi_ch_free( (void **)&(contkey.dptr) );
 	idl_unlock_list(a->ai_idl,key);
 	if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
diff --git a/ldap/servers/slapd/back-ldbm/idl_common.c b/ldap/servers/slapd/back-ldbm/idl_common.c
index b6d2e68..97b2e36 100644
--- a/ldap/servers/slapd/back-ldbm/idl_common.c
+++ b/ldap/servers/slapd/back-ldbm/idl_common.c
@@ -94,13 +94,13 @@ idl_allids( backend *be )
 }
 
 void
-idl_free( IDList *idl ) /* JCM - pass in ** */
+idl_free( IDList **idl )
 {
-	if ( idl == NULL ) {
+	if ((NULL == idl) || (NULL == *idl)) {
 		return;
 	}
 
-	slapi_ch_free((void**)&idl );
+	slapi_ch_free((void**)idl);
 }
 
 
@@ -163,7 +163,7 @@ idl_append_extend(IDList **orig_idl, ID id)
 		/* copy over the existing contents */
 		idl_new->b_nids = idl->b_nids;
 		memcpy(idl_new->b_ids, idl->b_ids, sizeof(ID) * idl->b_nids);
-		idl_free(idl);
+		idl_free(&idl);
 		idl = idl_new;
 	}
 
@@ -255,7 +255,7 @@ idl_intersection(
 	}
 
 	if ( ni == 0 ) {
-		idl_free( n );
+		idl_free( &n );
 		return( NULL );
 	}
 	n->b_nids = ni;
@@ -367,7 +367,7 @@ idl_notin(
 		}
 
 		if ( ni == n->b_nmax ) {
-			idl_free( n );
+			idl_free( &n );
 			*new_result = idl_allids( be );
 		} else {
 			n->b_nids = ni;
diff --git a/ldap/servers/slapd/back-ldbm/idl_new.c b/ldap/servers/slapd/back-ldbm/idl_new.c
index f0410f9..120153e 100644
--- a/ldap/servers/slapd/back-ldbm/idl_new.c
+++ b/ldap/servers/slapd/back-ldbm/idl_new.c
@@ -285,7 +285,7 @@ idl_new_fetch(
             idl_rc = idl_append_extend(&idl, id);
             if (idl_rc) {
                 LDAPDebug(LDAP_DEBUG_ANY, "unable to extend id list (err=%d)\n", idl_rc, 0, 0);
-                idl_free(idl); idl = NULL;
+                idl_free(&idl);
                 goto error;
             }
 
@@ -323,7 +323,7 @@ idl_new_fetch(
         if (idl_rc) {
             LDAPDebug1Arg(LDAP_DEBUG_ANY,
                           "unable to extend id list (err=%d)\n", idl_rc);
-            idl_free(idl); idl = NULL;
+            idl_free(&idl);
             goto error;
         }
 #if defined(DB_ALLIDS_ON_READ)    
@@ -339,7 +339,7 @@ idl_new_fetch(
 #endif
 
     if (ret != DB_NOTFOUND) {
-        idl_free(idl); idl = NULL;
+        idl_free(&idl);
         ldbm_nasty(filename,59,ret);
         goto error;
     }
@@ -348,7 +348,7 @@ idl_new_fetch(
 
     /* check for allids value */
     if (idl != NULL && idl->b_nids == 1 && idl->b_ids[0] == ALLID) {
-        idl_free(idl);
+        idl_free(&idl);
         idl = idl_allids(be);
         LDAPDebug(LDAP_DEBUG_TRACE, "idl_new_fetch %s returns allids\n", 
                   key.data, 0, 0);
@@ -501,7 +501,7 @@ idl_new_range_fetch(
         if (idl) {
             if ((lookthrough_limit != -1) &&
                 (idl->b_nids > (ID)lookthrough_limit)) {
-                idl_free(idl);
+                idl_free(&idl);
                 idl = idl_allids( be );
                 LDAPDebug0Args(LDAP_DEBUG_TRACE,
                           "idl_new_range_fetch - lookthrough_limit exceeded\n");
@@ -557,7 +557,7 @@ idl_new_range_fetch(
             if (idl_rc) {
                 LDAPDebug1Arg(LDAP_DEBUG_ANY,
                               "unable to extend id list (err=%d)\n", idl_rc);
-                idl_free(idl); idl = NULL;
+                idl_free(&idl);
                 goto error;
             }
 
@@ -618,7 +618,7 @@ idl_new_range_fetch(
         if (idl) {
             if ((lookthrough_limit != -1) &&
                 (idl->b_nids > (ID)lookthrough_limit)) {
-                idl_free(idl);
+                idl_free(&idl);
                 idl = idl_allids( be );
                 LDAPDebug0Args(LDAP_DEBUG_TRACE,
                           "idl_new_range_fetch - lookthrough_limit exceeded\n");
@@ -669,7 +669,7 @@ idl_new_range_fetch(
         if (idl_rc) {
             LDAPDebug1Arg(LDAP_DEBUG_ANY,
                           "unable to extend id list (err=%d)\n", idl_rc);
-            idl_free(idl); idl = NULL;
+            idl_free(&idl);
             goto error;
         }
 #if defined(DB_ALLIDS_ON_READ)    
@@ -688,7 +688,7 @@ idl_new_range_fetch(
         if (ret == DB_NOTFOUND) {
             ret = 0; /* normal case */
         } else {
-            idl_free(idl); idl = NULL;
+            idl_free(&idl);
             ldbm_nasty(filename,59,ret);
             goto error;
         }
@@ -696,7 +696,7 @@ idl_new_range_fetch(
 
     /* check for allids value */
     if (idl && (idl->b_nids == 1) && (idl->b_ids[0] == ALLID)) {
-        idl_free(idl);
+        idl_free(&idl);
         idl = idl_allids(be);
         LDAPDebug1Arg(LDAP_DEBUG_TRACE, "idl_new_fetch %s returns allids\n", 
                       cur_key.data);
diff --git a/ldap/servers/slapd/back-ldbm/import-merge.c b/ldap/servers/slapd/back-ldbm/import-merge.c
index 223f34f..a728165 100644
--- a/ldap/servers/slapd/back-ldbm/import-merge.c
+++ b/ldap/servers/slapd/back-ldbm/import-merge.c
@@ -169,8 +169,8 @@ static int import_merge_insert_input_queue(backend *be, import_merge_queue_entry
                     IDList *new_idl =
                         idl_union(be, current_entry->thang.payload.idl, idl);
 
-                    idl_free(current_entry->thang.payload.idl);
-                    idl_free(idl);
+                    idl_free(&(current_entry->thang.payload.idl));
+                    idl_free(&idl);
                     current_entry->thang.payload.idl = new_idl;
                     /* Add this file id into the entry's referenced list */
                     (current_entry->file_referenced_list)[fileno] = 1;
@@ -567,7 +567,7 @@ static int import_merge_one_file(ImportWorkerInfo *worker, int passes,
 		    ret = idl_store_block(be, output_file, &key,
 			thang.payload.idl, NULL, worker->index_info->ai);
 		    /* Free the key we got back from the queue */
-		    idl_free(thang.payload.idl);
+		    idl_free(&(thang.payload.idl));
 		    thang.payload.idl = NULL;
 		}
 		slapi_ch_free(&(key.data));
diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c
index 1e9f763..8344cfd 100644
--- a/ldap/servers/slapd/back-ldbm/import-threads.c
+++ b/ldap/servers/slapd/back-ldbm/import-threads.c
@@ -2355,7 +2355,7 @@ foreman_do_entrydn(ImportJob *job, FifoItem *fi)
          */
         if (IDL) {
             ID id = idl_firstid(IDL); /* entrydn is a single attr */
-            idl_free(IDL);
+            idl_free(&IDL);
             if (id != entry->ep_id) { /* case (2) */
                 import_log_notice(job, "Duplicated entrydn detected: \"%s\": "
                                        "Entry ID: (%d, %d)",
@@ -2381,7 +2381,7 @@ foreman_do_entrydn(ImportJob *job, FifoItem *fi)
                               "\"%s\" found at line %d of file \"%s\"",
                               slapi_entry_get_dn(entry->ep_entry),
                               fi->line, fi->filename);
-            idl_free(IDL);
+            idl_free(&IDL);
             /* skip this one */
             fi->bad = FIFOITEM_BAD;
             job->skipped++;
diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c
index 5610b49..ffeedef 100644
--- a/ldap/servers/slapd/back-ldbm/index.c
+++ b/ldap/servers/slapd/back-ldbm/index.c
@@ -197,7 +197,7 @@ index_put_idl(index_buffer_bin *bin,backend *be, DB_TXN *txn,struct attrinfo *a)
 			goto error;
 		}
 		slapi_ch_free( &(bin->key.data) );
-		idl_free(bin->value);
+		idl_free(&(bin->value));
 		/* If we're already at allids, store an allids block to prevent needless accumulation of blocks */
 		if (old_idl && ALLIDS(old_idl)) {
 			bin->value = idl_allids(be);
@@ -207,10 +207,10 @@ index_put_idl(index_buffer_bin *bin,backend *be, DB_TXN *txn,struct attrinfo *a)
 	}
 error:
 	if (old_idl) {
-		idl_free(old_idl);
+		idl_free(&old_idl);
 	}
 	if (new_idl && need_to_freed_new_idl) {
-		idl_free(new_idl);
+		idl_free(&new_idl);
 	}
 	dblayer_release_index_file( be, a, db );
 	return ret;
@@ -268,7 +268,7 @@ index_buffer_terminate(void *h)
 	for (i = 0; i < handle->buffer_size; i++) {
 		bin = &(handle->bins[i]);
 		if (bin->value) {
-			idl_free(bin->value);
+			idl_free(&(bin->value));
 			bin->value = NULL;
 		}
 		slapi_ch_free(&(bin->key.data));
@@ -1505,7 +1505,7 @@ index_range_read_ext(
             if (idl) {
                 if ((lookthrough_limit != -1) && 
                     (idl->b_nids > (ID)lookthrough_limit)) {
-                    idl_free(idl);
+                    idl_free(&idl);
                     idl = idl_allids( be );
                     LDAPDebug0Args(LDAP_DEBUG_TRACE,
                                "index_range_read lookthrough_limit exceeded\n");
@@ -1534,7 +1534,7 @@ index_range_read_ext(
              */
             if ( slapi_op_abandoned( pb )) {
                 if (NULL != idl) {
-                    idl_free(idl);
+                    idl_free(&idl);
                     idl = NULL;
                 }
                 LDAPDebug0Args(LDAP_DEBUG_TRACE,
@@ -1574,7 +1574,7 @@ index_range_read_ext(
                 /* idl tmp only contains one id */
                 /* append it at the end here; sort idlist at the end */
                 if (ALLIDS(tmp)) {
-                    idl_free(idl);
+                    idl_free(&idl);
                     idl = tmp;
                 } else {
                     ID id;
@@ -1586,7 +1586,7 @@ index_range_read_ext(
                                        1097, *err);
                         }
                     }
-                    idl_free(tmp);
+                    idl_free(&tmp);
                 }
                 if (ALLIDS(idl)) {
                     LDAPDebug0Args(LDAP_DEBUG_TRACE,
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
index 46d30eb..d4039e4 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
@@ -1100,7 +1100,7 @@ entryrdn_get_subordinates(backend *be,
     
 bail:
     if (rc && subordinates && *subordinates) {
-        idl_free(*subordinates);
+        idl_free(subordinates);
     }
     slapi_ch_free_string(&keybuf);
     slapi_ch_free((void **)&elem);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
index b1b6cc9..472c2f7 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -1524,7 +1524,7 @@ common_return:
     slapi_ch_free((void**)&child_dns);
     if (ldap_result_matcheddn && 0 != strcmp(ldap_result_matcheddn, "NULL"))
         slapi_ch_free((void**)&ldap_result_matcheddn);
-    idl_free(children);
+    idl_free(&children);
     slapi_sdn_done(&dn_newdn);
     slapi_sdn_done(&dn_newrdn);
     slapi_sdn_done(&dn_parentdn);
@@ -2238,7 +2238,7 @@ moddn_get_children(back_txn *ptxn,
                 }
             }
         } while (id!=NOID);
-        idl_free(candidates);
+        idl_free(&candidates);
         slapi_sdn_done(&parentsdn);
     }
     
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
index d0563bd..a31b450 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -48,6 +48,16 @@
 #include "back-ldbm.h"
 #include "vlv_srch.h"
 
+/* 
+ * Used for ldap_result passed to ldbm_back_search_cleanup.
+ * If (ldap_result == LDBM_SRCH_DEFAULT_RESULT) || (ldap_result == LDAP_SUCCESS), 
+ * don't call slapi_send_ldap_result.
+ * Note: mozldap ldap_result codes are all positive; openldap result codes could
+ *       be netative values.  OL (-1) is LDAP_SERVER_DOWN.  Thus, it's safe to 
+ *       borrow the value here.
+ */
+#define LDBM_SRCH_DEFAULT_RESULT (-1)
+
 /* prototypes */
 static int build_candidate_list( Slapi_PBlock *pb, backend *be,
         struct backentry *e, const char * base, int scope,
@@ -162,12 +172,14 @@ ldbm_back_search_cleanup(Slapi_PBlock *pb,
                          char* ldap_result_description,
                          int function_result,
                          struct vlv_request *vlv_request_control,
-                         struct backentry *e)
+                         struct backentry *e,
+                         IDList *candidates)
 {
     int estimate = 0; /* estimated search result count */
     backend *be;
     ldbm_instance *inst;
     back_search_result_set *sr = NULL;
+    int free_candidates = 1;
 
     slapi_pblock_get( pb, SLAPI_BACKEND, &be );
     inst = (ldbm_instance *) be->be_instance_info;
@@ -180,20 +192,27 @@ ldbm_back_search_cleanup(Slapi_PBlock *pb,
     {
         sort_spec_free(sort_control);
     }
-    if(ldap_result>=LDAP_SUCCESS)
-    {
+    if ((ldap_result != LDBM_SRCH_DEFAULT_RESULT) && (ldap_result != LDAP_SUCCESS)) {
         slapi_send_ldap_result( pb, ldap_result, NULL, ldap_result_description, 0, NULL );
     }
     /* code to free the result set if we don't need it */
     /* We get it and check to see if the structure was ever used */
     slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &sr);
     if (sr) {
-        if (function_result) {
+        if (function_result) { /* failed case */
             slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET_SIZE_ESTIMATE, &estimate);
             slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, NULL);
+            if (sr->sr_candidates == candidates) {
+                free_candidates = 0;
+            }
             delete_search_result_set(pb, &sr);
+        } else if (sr->sr_candidates == candidates) { /* succeeded case */
+            free_candidates = 0;
         }
     }
+    if (free_candidates) {
+        idl_free(&candidates);
+    }
     if (vlv_request_control)
     {
         berval_done(&vlv_request_control->value);
@@ -336,7 +355,7 @@ ldbm_back_search( Slapi_PBlock *pb )
     back_search_result_set *sr = NULL;
 
     /* Fix for bugid #394184, SD, 20 Jul 00 */
-    int tmp_err = -1;  /* must be lower than LDAP_SUCCESS */
+    int tmp_err = LDBM_SRCH_DEFAULT_RESULT;
     char * tmp_desc = NULL;
     /* end Fix for defect #394184 */
 
@@ -401,7 +420,7 @@ ldbm_back_search( Slapi_PBlock *pb )
                      */
                     return ldbm_back_search_cleanup(pb, li, sort_control, 
                                 LDAP_UNAVAILABLE_CRITICAL_EXTENSION, "Sort Control", 
-                                SLAPI_FAIL_GENERAL, NULL, NULL);
+                                SLAPI_FAIL_GENERAL, NULL, NULL, candidates);
                 } else {
                     PRUint64 conn_id;
                     int op_id;
@@ -436,7 +455,7 @@ ldbm_back_search( Slapi_PBlock *pb )
                          */
                         return ldbm_back_search_cleanup(pb, li, sort_control,
                                 LDAP_UNAVAILABLE_CRITICAL_EXTENSION, "VLV Control", SLAPI_FAIL_GENERAL,
-                                &vlv_request_control, NULL);
+                                &vlv_request_control, NULL, candidates);
                     } else {
                         PRUint64 conn_id;
                         int op_id;
@@ -470,7 +489,7 @@ ldbm_back_search( Slapi_PBlock *pb )
                             /* Client isn't allowed to do this. */
                             return ldbm_back_search_cleanup(pb, li, sort_control,
                                     rc, "VLV Control", SLAPI_FAIL_GENERAL,
-                                    &vlv_request_control, NULL);
+                                    &vlv_request_control, NULL, candidates);
                         }
                     }
                     /*
@@ -485,7 +504,7 @@ ldbm_back_search( Slapi_PBlock *pb )
                 /* Can't have a VLV control without a SORT control */
                 return ldbm_back_search_cleanup(pb, li, sort_control, 
                                 LDAP_SORT_CONTROL_MISSING, "VLV Control", 
-                                SLAPI_FAIL_GENERAL, &vlv_request_control, NULL);
+                                SLAPI_FAIL_GENERAL, &vlv_request_control, NULL, candidates);
             }
         }
     }
@@ -538,13 +557,13 @@ ldbm_back_search( Slapi_PBlock *pb )
             {
                 return ldbm_back_search_cleanup(pb, li, sort_control,
                             LDAP_UNWILLING_TO_PERFORM, ctrlstr,
-                            SLAPI_FAIL_GENERAL, &vlv_request_control, NULL);
+                            SLAPI_FAIL_GENERAL, &vlv_request_control, NULL, candidates);
             }
             else
             {
                 return ldbm_back_search_cleanup(pb, li, sort_control,
                             LDAP_VIRTUAL_LIST_VIEW_ERROR, ctrlstr,
-                            SLAPI_FAIL_GENERAL, &vlv_request_control, NULL);
+                            SLAPI_FAIL_GENERAL, &vlv_request_control, NULL, candidates);
             }
         }
         else
@@ -559,7 +578,7 @@ ldbm_back_search( Slapi_PBlock *pb )
                 sort_make_sort_response_control(pb, LDAP_UNWILLING_TO_PERFORM, NULL);
                 return ldbm_back_search_cleanup(pb, li, sort_control,
                             LDAP_UNAVAILABLE_CRITICAL_EXTENSION, ctrlstr,
-                            SLAPI_FAIL_GENERAL, &vlv_request_control, NULL);
+                            SLAPI_FAIL_GENERAL, &vlv_request_control, NULL, candidates);
             }
             else /* vlv and sorting are not critical, so ignore the control */
             {
@@ -593,7 +612,7 @@ ldbm_back_search( Slapi_PBlock *pb )
         {
             /* error or referral sent by find_entry */
             return ldbm_back_search_cleanup(pb, li, sort_control, 
-                            -1, NULL, 1, &vlv_request_control, NULL);
+                            LDBM_SRCH_DEFAULT_RESULT, NULL, 1, &vlv_request_control, NULL, candidates);
         }
     }
 
@@ -616,6 +635,7 @@ ldbm_back_search( Slapi_PBlock *pb )
         /*
          * Build a list of IDs for this entry and scope
          */    
+        vlv_response_control.result = LDAP_SUCCESS;
         if ((NULL != controls) && (sort) && (vlv)) {
             /* This candidate list is for vlv, no need for sort only. */
             switch (vlv_search_build_candidate_list(pb, basesdn, &vlv_rc,
@@ -626,12 +646,12 @@ ldbm_back_search( Slapi_PBlock *pb )
                 return ldbm_back_search_cleanup(pb, li, sort_control,
                                                 vlv_rc, "VLV Control",
                                                 SLAPI_FAIL_GENERAL, 
-                                                &vlv_request_control, e);
+                                                &vlv_request_control, e, candidates);
             case VLV_BLD_LIST_FAILED:
                 return ldbm_back_search_cleanup(pb, li, sort_control,
                                                 vlv_response_control.result,
                                                 NULL, SLAPI_FAIL_GENERAL,
-                                                &vlv_request_control, e);
+                                                &vlv_request_control, e, candidates);
                 
             case LDAP_SUCCESS:
                 /* Log to the access log the particulars of this sort request */
@@ -652,7 +672,7 @@ ldbm_back_search( Slapi_PBlock *pb )
                                                     LDAP_OPERATIONS_ERROR,
                                                     "Sort Response Control",
                                                     SLAPI_FAIL_GENERAL,
-                                                    &vlv_request_control, e);
+                                                    &vlv_request_control, e, candidates);
                 }
             }
         }
@@ -663,9 +683,9 @@ ldbm_back_search( Slapi_PBlock *pb )
             if (rc)
             {
                 /* Error result sent by build_candidate_list */
-                return ldbm_back_search_cleanup(pb, li, sort_control, -1,
-                                                NULL, rc, 
-                                                &vlv_request_control, e);
+                return ldbm_back_search_cleanup(pb, li, sort_control, 
+                                                LDBM_SRCH_DEFAULT_RESULT, NULL, rc, 
+                                                &vlv_request_control, e, candidates);
             }
             /*
              * If we're sorting then we must check what administrative
@@ -691,23 +711,33 @@ ldbm_back_search( Slapi_PBlock *pb )
              * If we're presenting a virtual list view, then apply the
              * search filter before sorting.
              */
-            if (virtual_list_view && (NULL != candidates))
-            {
+            if (virtual_list_view && candidates) {
                 IDList *idl = NULL;
                 Slapi_Filter *filter = NULL;
                 slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
                 rc = vlv_filter_candidates(be, pb, candidates, basesdn,
-                                          scope, filter, &idl,
-                                          lookthrough_limit, time_up);
-                if (rc == 0) {
-                    idl_free(candidates);
-                    candidates= idl;
-                }
-                else
-                {
+                                           scope, filter, &idl,
+                                           lookthrough_limit, time_up);
+                switch (rc) {
+                case LDAP_SUCCESS:  /* Everything OK */
+                case LDAP_TIMELIMIT_EXCEEDED:  /* Timeout */
+                case LDAP_ADMINLIMIT_EXCEEDED:  /* Admin limit exceeded */
+                    vlv_response_control.result = rc;
+                    idl_free(&candidates);
+                    candidates = idl;
+                    break;
+                case LDAP_UNWILLING_TO_PERFORM:  /* Too hard */
+                default: 
                     return ldbm_back_search_cleanup(pb, li, sort_control,
                                                     rc, NULL, -1, 
-                                                    &vlv_request_control, e);
+                                                    &vlv_request_control, e, candidates);
+                }
+                if (is_vlv_critical && rc) {
+                    idl_free(&candidates);
+                    candidates = idl_alloc(0);
+                    tmp_err = rc;
+                    tmp_desc = "VLV Response Control";
+                    goto vlv_bail;
                 }
             }
             /*
@@ -725,7 +755,7 @@ ldbm_back_search( Slapi_PBlock *pb )
                     return ldbm_back_search_cleanup(pb, li, sort_control,
                                              LDAP_PROTOCOL_ERROR,
                                              "Sort Response Control", -1,
-                                             &vlv_request_control, e);
+                                             &vlv_request_control, e, candidates);
                 }
               }
               else
@@ -759,21 +789,24 @@ ldbm_back_search( Slapi_PBlock *pb )
                 /* replace the hard coded return value by the appropriate 
                  * LDAP error code */
                 switch (sort_return_value) {
-                   case LDAP_SUCCESS:  /* Everything OK */
-                    vlv_response_control.result= LDAP_SUCCESS;
+                   case LDAP_SUCCESS:
+                    /* 
+                     * we don't want to override an error from vlv 
+                     * vlv_response_control.result= LDAP_SUCCESS; 
+                     */
                     break;
                 case LDAP_PROTOCOL_ERROR:  /* A protocol error */
                     return ldbm_back_search_cleanup(pb, li, sort_control,
                                                     LDAP_PROTOCOL_ERROR,
                                                     "Sort Control", -1,
-                                                    &vlv_request_control, e);
+                                                    &vlv_request_control, e, candidates);
                 case LDAP_UNWILLING_TO_PERFORM:  /* Too hard */
                 case LDAP_OPERATIONS_ERROR:  /* Operation error */
                 case LDAP_TIMELIMIT_EXCEEDED:  /* Timeout */
-                    vlv_response_control.result= LDAP_TIMELIMIT_EXCEEDED;
-                    break;
                 case LDAP_ADMINLIMIT_EXCEEDED:  /* Admin limit exceeded */
-                    vlv_response_control.result = LDAP_ADMINLIMIT_EXCEEDED;
+                    if (!vlv_response_control.result) {
+                        vlv_response_control.result = sort_return_value;
+                    }
                     break;
                 case LDAP_OTHER:  /* Abandoned */
                     abandoned = 1; /* So that we don't return a result code */
@@ -792,11 +825,10 @@ ldbm_back_search( Slapi_PBlock *pb )
                 /* Fix for bugid #394184, SD, 05 Jul 00 */
                 /* we were not actually returning unavailableCriticalExtension;
                  now fixed (hopefully !) */
-                if (is_sorting_critical && (0 != sort_return_value))
-                {
-                    idl_free(candidates);
+                if (is_sorting_critical && sort_return_value) {
+                    idl_free(&candidates);
                     candidates = idl_alloc(0);
-                    tmp_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+                    tmp_err = sort_return_value;
                     tmp_desc = "Sort Response Control";
                 }
                 /* end Fix for bugid #394184 */
@@ -806,9 +838,9 @@ ldbm_back_search( Slapi_PBlock *pb )
                                           sort_return_value, sort_error_type ) )
                 {
                     return ldbm_back_search_cleanup(pb, li, sort_control,
-                                             (abandoned?-1:LDAP_PROTOCOL_ERROR),
+                                             (abandoned?LDBM_SRCH_DEFAULT_RESULT:LDAP_PROTOCOL_ERROR),
                                              "Sort Response Control", -1,
-                                             &vlv_request_control, e);
+                                             &vlv_request_control, e, candidates);
                 }
               }
             }
@@ -816,10 +848,9 @@ ldbm_back_search( Slapi_PBlock *pb )
              * If we're presenting a virtual list view, then the candidate list
              * must be trimmed down to just the range of entries requested.
              */
-            if (virtual_list_view)
-            {
-                if (NULL != candidates && candidates->b_nids>0)
-                {
+            if (virtual_list_view) {
+                if (candidates && (candidates->b_nids > 0) &&
+                    !vlv_response_control.result) {
                     IDList *idl= NULL;
                     back_txn txn = {NULL};
                     slapi_pblock_get(pb, SLAPI_TXN, &txn.back_txn_txn);
@@ -828,7 +859,7 @@ ldbm_back_search( Slapi_PBlock *pb )
                         &vlv_request_control, &idl, &vlv_response_control, &txn);
                     if(vlv_response_control.result==0)
                     {
-                        idl_free(candidates);
+                        idl_free(&candidates);
                         candidates = idl;
                     }
                     else
@@ -836,26 +867,23 @@ ldbm_back_search( Slapi_PBlock *pb )
                         return ldbm_back_search_cleanup(pb, li, sort_control,
                                                     vlv_response_control.result,
                                                     NULL, -1, 
-                                                    &vlv_request_control, e);
+                                                    &vlv_request_control, e, candidates);
                     }
-                }
-                else
-                {
+                } else {
                     vlv_response_control.targetPosition = 0;
                     vlv_response_control.contentCount = 0;
-                    vlv_response_control.result = LDAP_SUCCESS;
+                    /* vlv_response_control.result = LDAP_SUCCESS; Don't override */
                 }
             }
         }
-        if (virtual_list_view)
-        {
-            if(LDAP_SUCCESS != 
-                         vlv_make_response_control( pb, &vlv_response_control ))
-            {
+vlv_bail:
+        if (virtual_list_view) {
+            if (LDAP_SUCCESS != 
+                vlv_make_response_control( pb, &vlv_response_control )) {
                 return ldbm_back_search_cleanup(pb, li, sort_control,
-                                             (abandoned?-1:LDAP_PROTOCOL_ERROR),
+                                             (abandoned?LDBM_SRCH_DEFAULT_RESULT:LDAP_PROTOCOL_ERROR),
                                              "VLV Response Control", -1,
-                                             &vlv_request_control, e);
+                                             &vlv_request_control, e, candidates);
             }
             /* Log the VLV operation */
             vlv_print_access_log(pb,&vlv_request_control,&vlv_response_control);
@@ -885,7 +913,7 @@ ldbm_back_search( Slapi_PBlock *pb )
             PR_Unlock(inst->inst_config_mutex);
 
             if (ri) {
-                idl_free(candidates);
+                idl_free(&candidates);
                 candidates = idl_alloc(0);
                 tmp_err = LDAP_UNWILLING_TO_PERFORM;
                 tmp_desc = "Search is not indexed";
@@ -948,10 +976,10 @@ ldbm_back_search( Slapi_PBlock *pb )
     }
 
     /* Fix for bugid #394184, SD, 05 Jul 00 */
-    /* tmp_err == -1: no error */
+    /* tmp_err == LDBM_SRCH_DEFAULT_RESULT: no error */
     return ldbm_back_search_cleanup(pb, li, sort_control, tmp_err, tmp_desc,
-                                    (tmp_err  == -1 ? 0 : -1), 
-                                    &vlv_request_control, NULL);
+                                    (tmp_err == LDBM_SRCH_DEFAULT_RESULT ? 0 : LDBM_SRCH_DEFAULT_RESULT), 
+                                    &vlv_request_control, NULL, candidates);
     /* end Fix for bugid #394184 */
 }
 
@@ -1212,14 +1240,14 @@ subtree_candidates(
                                          e->ep_id, &descendants, &txn, 0);
             idl_insert(&descendants, e->ep_id);
             candidates = idl_intersection(be, candidates, descendants);
-            idl_free(tmp);
-            idl_free(descendants);
+            idl_free(&tmp);
+            idl_free(&descendants);
         } else if (!has_tombstone_filter) {
             *err = ldbm_ancestorid_read_ext(be, &txn, e->ep_id, &descendants, allidslimit);
             idl_insert(&descendants, e->ep_id);
             candidates = idl_intersection(be, candidates, descendants);
-            idl_free(tmp);
-            idl_free(descendants);
+            idl_free(&tmp);
+            idl_free(&descendants);
         } /* else == has_tombstone_filter: do nothing */
     }
 
@@ -1847,7 +1875,7 @@ delete_search_result_set( Slapi_PBlock *pb, back_search_result_set **sr )
     }
     if ( NULL != (*sr)->sr_candidates )
     {
-        idl_free( (*sr)->sr_candidates );
+        idl_free( &((*sr)->sr_candidates) );
     }
     rc = slapi_filter_apply((*sr)->sr_norm_filter, ldbm_search_free_compiled_filter,
                             NULL, &filt_errs);
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
index c4c9414..1d1b2dc 100644
--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
@@ -292,7 +292,7 @@ add_op_attrs(Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *ep,
             if ( (idl = index_read( be, LDBM_ENTRYDN_STR, indextype_EQUALITY, 
                                     &bv, NULL, &err )) != NULL ) {
                 pid = idl_firstid( idl );
-                idl_free( idl );
+                idl_free( &idl );
             } else {
                 /* empty idl */
                 if ( 0 != err && DB_NOTFOUND != err ) {
@@ -609,7 +609,7 @@ int update_subordinatecounts(backend *be, ImportJob *job, DB_TXN *txn)
                     /* We get the count from the IDL */
                     sub_count = idl->b_nids;
                 }
-                idl_free(idl);
+                idl_free(&idl);
             } 
             /* Did we get the count ? */
             if (found_count) {
@@ -914,8 +914,7 @@ static IDList *ldbm_fetch_subtrees(backend *be, char **include, int *err)
                 continue;
             }
             id = idl_firstid(idl);
-            idl_free(idl);
-            idl = NULL;
+            idl_free(&idl);
         }
 
         /*
@@ -953,8 +952,8 @@ static IDList *ldbm_fetch_subtrees(backend *be, char **include, int *err)
             idltotal = idl;
         } else if (idl) {
             idltmp = idl_union(be, idltotal, idl);
-            idl_free(idltotal);
-            idl_free(idl);
+            idl_free(&idltotal);
+            idl_free(&idl);
             idltotal = idltmp;
         }
     } /* for (i = 0; include[i]; i++) */
@@ -1356,8 +1355,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb )
             /* allids list is no help at all -- revert to trawling
              * the whole list. */
             ok_index = 0;
-            idl_free(idl);
-            idl = NULL;
+            idl_free(&idl);
         }
         idindex = 0;
     }
@@ -1613,7 +1611,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb )
     }
 bye:
     if (idl) {
-        idl_free(idl);
+        idl_free(&idl);
     }
     if (dbc) {
         dbc->c_close(dbc);
@@ -1644,7 +1642,7 @@ bye:
     }
 
     ldbm_back_free_incl_excl(include_suffix, exclude_suffix);
-    idl_free(eargs.pre_exported_idl);
+    idl_free(&(eargs.pre_exported_idl));
     
     return( return_value );
 }
@@ -1958,8 +1956,7 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
             }
         } else if (ALLIDS(idl)) {
             /* that's no help. */
-            idl_free(idl);
-            idl = NULL;
+            idl_free(&idl);
         }
     }
 
@@ -2468,7 +2465,7 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
 err_out:
     backentry_free( &ep ); /* if ep or *ep is NULL, it does nothing */
     if (idl) {
-        idl_free(idl);
+        idl_free(&idl);
     } else {
         dbc->c_close(dbc);
     }
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 3870ce5..561a208 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -243,7 +243,7 @@ struct backentry * id2entry( backend *be, ID id, back_txn *txn, int *err );
  * idl.c
  */
 IDList * idl_alloc( NIDS nids );
-void idl_free( IDList *idl );
+void idl_free( IDList **idl );
 NIDS idl_length(IDList *idl);
 int idl_is_allids(IDList *idl);
 int idl_append(IDList *idl, ID id);
diff --git a/ldap/servers/slapd/back-ldbm/seq.c b/ldap/servers/slapd/back-ldbm/seq.c
index a75879c..29b3f6a 100644
--- a/ldap/servers/slapd/back-ldbm/seq.c
+++ b/ldap/servers/slapd/back-ldbm/seq.c
@@ -245,7 +245,7 @@ retry:
 				key.flags = 0;
 				for (retry_count = 0; retry_count < IDL_FETCH_RETRY_COUNT; retry_count++) {
 					err = NEW_IDL_DEFAULT;
-					idl_free(idl);
+					idl_free(&idl);
 					idl = idl_fetch( be, db, &key, parent_txn, ai, &err );
 					if(err == DB_LOCK_DEADLOCK) {
 						ldbm_nasty("ldbm_back_seq deadlock retry", 1600, err);
@@ -319,7 +319,7 @@ retry:
 		    }
 		    CACHE_RETURN( &inst->inst_cache, &e );
 		}
-		idl_free( idl );
+		idl_free( &idl );
 	}
 
 	dblayer_release_index_file( be, ai, db );
diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c
index 83b321a..d061bf2 100644
--- a/ldap/servers/slapd/back-ldbm/vlv.c
+++ b/ldap/servers/slapd/back-ldbm/vlv.c
@@ -1122,7 +1122,7 @@ int vlv_build_idl(PRUint32 start, PRUint32 stop, DB *db, DBC *dbc,
     goto done;
 
 error:
-    if (idl) idl_free(idl);
+    if (idl) idl_free(&idl);
 
 done:
     return rc;
-- 
1.8.3.1

