Hello
I found a bug in slapo-nops: if all modify operations are idempotent, I end up with op->orm_modlist being NULL, and slapd stops there.
Here is the current code in slapo-nops that deals with that condition: if ((m = op->orm_modlist) == NULL) { op->o_bd->bd_info = (BackendInfo *)(on->on_info); send_ldap_error(op, rs, LDAP_SUCCESS, ""); return(rs->sr_err); }
Obviously, this is not doing what it should. I need to abort the operation while returning LDAP_SUCCESS to the client. How should this be done?
Emmanuel Dreyfus wrote:
Hello
I found a bug in slapo-nops: if all modify operations are idempotent, I end up with op->orm_modlist being NULL, and slapd stops there.
Here is the current code in slapo-nops that deals with that condition: if ((m = op->orm_modlist) == NULL) { op->o_bd->bd_info = (BackendInfo *)(on->on_info);
Delete that line above.
send_ldap_error(op, rs, LDAP_SUCCESS, ""); return(rs->sr_err); }
Obviously, this is not doing what it should. I need to abort the operation while returning LDAP_SUCCESS to the client. How should this be done?
Howard Chu hyc@symas.com wrote:
op->o_bd->bd_info = (BackendInfo *)(on->on_info);
Delete that line above.
I now get a memory fault, because I jump to a NULL pointer. Here is the backtrace: #0 0x00000000 in ?? () #1 0xbb73bb12 in nops_modify (op=0x84b5c00, rs=0xb85ffd70) at nops.c:139 139 send_ldap_error(op, rs, LDAP_SUCCESS, "");
send_ldap_error is a macro: #define send_ldap_error( op, rs, err, text ) do { \ (rs)->sr_err = err; (rs)->sr_text = text; \ ((op)->o_conn->c_send_ldap_result)( op, rs ); \ } while (0)
And, indeed: (gdb) print op->o_hdr->oh_conn->c_send_ldap_result $5 = (SEND_LDAP_RESULT *) 0
I assume it must be something really stupid for someone familiar enough with the code :-)
Howard Chu hyc@symas.com wrote:
Here is the current code in slapo-nops that deals with that condition: if ((m = op->orm_modlist) == NULL) { op->o_bd->bd_info = (BackendInfo *)(on->on_info);
Delete that line above.
Right, I had a problem because I was not building against the same slap.h the server was built with.
Now, another problem: this does not really cancel the operation:
if ((m = op->orm_modlist) == NULL) { send_ldap_error(op, rs, LDAP_SUCCESS, ""); return(rs->sr_err); }
There is an accesslog overlay after the nops overlay, and if the code path above is executed, it will fire an assertion in accesslog code because the modify set is empty.
I assume that having accesslog before nops will help, but OTOH, one of the goal of nops is to avoid overloading accesslog with junk changes.
Emmanuel Dreyfus wrote:
Howard Chuhyc@symas.com wrote:
Here is the current code in slapo-nops that deals with that condition: if ((m = op->orm_modlist) == NULL) { op->o_bd->bd_info = (BackendInfo *)(on->on_info);
Delete that line above.
Right, I had a problem because I was not building against the same slap.h the server was built with.
Now, another problem: this does not really cancel the operation:
if ((m = op->orm_modlist) == NULL) { send_ldap_error(op, rs, LDAP_SUCCESS, ""); return(rs->sr_err); }
There is an accesslog overlay after the nops overlay, and if the code path above is executed, it will fire an assertion in accesslog code because the modify set is empty.
As I said before, you hadn't provided enough details about your configuration. Next time you ask a question like this, send your slapd.conf as requested.
I assume that having accesslog before nops will help, but OTOH, one of the goal of nops is to avoid overloading accesslog with junk changes.
What are you really trying to accomplish here? In what operating context? Provide more info if you want to get any help.
Hello
If all the modifications are removed by slapo-nops, I end up with op->orm_modlist == NULL. slapo-nops will attempt to cancel the operation, with this code: if ((m = op->orm_modlist) == NULL) { op->o_bd->bd_info = (BackendInfo *)(on->on_info); send_ldap_error(op, rs, LDAP_SUCCESS, ""); return(rs->sr_err); }
But if slapo-accesslog is also configured, slapd will exit with an assertion: assertion "a->a_vals[0].bv_val != NULL" failed: file "schema_check.c", line 89, function "entry_schema_check"
Here is the offending code: /* misc attribute checks */ for ( a = e->e_attrs; a != NULL; a = a->a_next ) { const char *type = a->a_desc->ad_cname.bv_val;
/* there should be at least one value */ assert( a->a_vals != NULL ); assert( a->a_vals[0].bv_val != NULL );
Here is the backtrace
#0 0xbb81823f in kill () from /lib/libc.so.12 #1 0xbb8b4a64 in abort () from /lib/libc.so.12 #2 0xbb876dde in __assert13 () from /lib/libc.so.12 #3 0x0809edcf in entry_schema_check () #4 0x080ff6f7 in bdb_add () #5 0x081394e0 in accesslog_initialize () #6 0x080cb535 in glue_sub_add () #7 0x0807f979 in slap_req2res () #8 0x0808221b in slap_read_controls () #9 0x08082c9d in slap_send_ldap_result () #10 0xbb76ab3c in nops_modify () from /usr/pkg/lib/openldap/nops.so.0 #11 0x080cb6e3 in overlay_op_walk () #12 0x080cbc7c in overlay_destroy_one () #13 0x080877b7 in fe_op_modify () #14 0x08087ecd in do_modify () #15 0x080724fd in connection_hangup () #16 0x08072acc in connection_hangup () #17 0xbbbb8c3f in ldap_int_thread_pool_wrapper () from /usr/pkg/lib/libldap_r-2.4.so.2 #18 0xbb8e762d in pthread_join () from /usr/lib/libpthread.so.0 #19 0xbb839a2c in swapcontext () from /lib/libc.so.12
Peeking with gdb, I can see the problem is with attribute reqOld having a NULL value.
I would say that slapo-nops does not cancel the proper way, since slapo-accesslog still think it has something to log. Any idea?
Emmanuel Dreyfus wrote:
Hello
If all the modifications are removed by slapo-nops, I end up with op->orm_modlist == NULL. slapo-nops will attempt to cancel the operation, with this code: if ((m = op->orm_modlist) == NULL) { op->o_bd->bd_info = (BackendInfo *)(on->on_info); send_ldap_error(op, rs, LDAP_SUCCESS, ""); return(rs->sr_err); }
But if slapo-accesslog is also configured, slapd will exit with an assertion: assertion "a->a_vals[0].bv_val != NULL" failed: file "schema_check.c", line 89, function "entry_schema_check"
You need to make sure that your overlays are configured such that your nops executes before accesslog, to prevent accesslog from attempting to log anything.
Also, in your cancel code, you need to set op->o_callback to NULL before calling send_ldap_error, to make sure that no other overlays run. Then set it back to whatever it was, before returning.
On Mon, Mar 16, 2009 at 12:53:18AM -0700, Howard Chu wrote:
You need to make sure that your overlays are configured such that your nops executes before accesslog, to prevent accesslog from attempting to log anything.
Also, in your cancel code, you need to set op->o_callback to NULL before calling send_ldap_error, to make sure that no other overlays run. Then set it back to whatever it was, before returning.
Without modifying the code, configuring nops after accesslog in slapd.conf does prevent it from crashing.
Setting o_callback to NULL fixes the crash. And it seems to fix it regardless of overlay order: whether nops is configured before or after accesslog, it works fine with that cancel code:
if ((m = op->orm_modlist) == NULL) { slap_callback *cb = op->o_callback;
op->o_bd->bd_info = (BackendInfo *)(on->on_info); op->o_callback = NULL; send_ldap_error(op, rs, LDAP_SUCCESS, ""); op->o_callback = cb;
return (rs->sr_err); }