I've been trying to factor this MUSTRELEASE/MUSTBEFREED stuff out to some macros. Easier said than done, I ended up with the macro monstrosity below. Do I put that in slap.h? Or a separate slap-response.h file?
Generally the idea is that most code which modifies rs->sr_<entry/matched/ref/ctrls> (as opposed to initializing) should use these macros, which obey sr_flag and dispose of the old value if needed. There won't be that many callers actually, mostly overlays. There is overlay code which need to be rearranged a bit or which can't use this, and there is overlay code I don't understand at all and don't dare touch.
Oh, and this seems to be wrong for how sr_ctrls are set up, which seems to be allocated differently some places. I'm just including that for reference for now, won't commit it yet in any case.
Finally, code which aborts normal processing of some response and instead send an error often needs to be fixed - it often doesn't flush SlapReply data, and the data to be flushed and maybe freeed can be lost because it's overwritten. Generally I think code which modifies sr_type (or in some cases calls a function which will do so) should be responsible for flushing old SlapReply data first.
#define REP_ENTRY_MUSTFLUSH (REP_ENTRY_MUSTBEFREED|REP_ENTRY_MUSTRELEASE) #define REP_ENTRY_MASK (REP_ENTRY_MODIFIABLE |REP_ENTRY_MUSTFLUSH) #define REP_MATCHED_MUSTFLUSH REP_MATCHED_MUSTBEFREED #define REP_REF_MUSTFLUSH REP_REF_MUSTBEFREED #define REP_CTRLS_MUSTFLUSH REP_CTRLS_MUSTBEFREED
/* Macros updating freeable members of SlapReply, mostly for overlays. */
/* * Ensure rs->sr_entry is modifiable, by duplicating it if necessary. * Obey sr_flags. Set REP_ENTRY_<MODIFIABLE, and MUSTBEFREED if duplicated>. * Do <postmodActions> if the entry was replaced. */ #define RS_MODIFIABLE_ENTRY(op, rs, on, postmodActions) do { \ SlapReply *const rmeRS = (rs); \ if ( rmeRS->sr_flags & REP_ENTRY_MODIFIABLE ) break; \ RS_REPLACE_ENTRY( op, rmeRS, on, entry_dup( rmeRS->sr_entry ), 0 ); \ rmeRS->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; \ postmodActions; \ } while (0)
/* Reset rs->sr_<member> if REP_<member>_MUSTBEFREED/MUSTRELEASE says so. */ #define RS_FLUSH_ENTRY(op, rs, on) RS_FLUSH(ENTRY, op, rs, on, 1, {}, {}) #define RS_FLUSH_CTRLS(op, rs) RS_FLUSH(CTRLS, op, rs, -, 1, {}, {}) #define RS_FLUSH_MATCHED( rs) RS_FLUSH(MATCHED, -, rs, -, 1, {}, {}) #define RS_FLUSH_REF( rs) RS_FLUSH(REF, -, rs, -, 1, {}, {})
/* Flush and set rs->sr_<member>. Set REP_<member>_MUSTBEFREED if <isDup>. */ #define RS_REPLACE_ENTRY(op,rs,on,v,isDup) RS_REPLACE(ENTRY,op,rs,on, v,isDup) #define RS_REPLACE_CTRLS(op,rs,v,isDup) RS_REPLACE(CTRLS, op,rs,-, v,isDup) #define RS_REPLACE_MATCHED( rs,v,isDup) RS_REPLACE(MATCHED, -,rs,-, v,isDup) #define RS_REPLACE_REF( rs,v,isDup) RS_REPLACE(REF, -,rs,-, v,isDup)
/* Helpers for the above */ #define SR_ENTRY sr_entry #define SR_CTRLS sr_ctrls #define SR_MATCHED sr_matched #define SR_REF sr_ref typedef Entry *SR_ENTRY_t; typedef LDAPControl **SR_CTRLS_t; typedef const char *SR_MATCHED_t; typedef BerVarray SR_REF_t; #define RS_FREE_ENTRY(op, rs, on)\ if ((rs)->sr_flags & REP_ENTRY_MUSTBEFREED) { \ assert (!(rs)->sr_flags & REP_ENTRY_MUSTRELEASE); \ entry_free((rs)->sr_entry); \ } \ else if (on == NULL) be_entry_release_rw(op, (rs)->sr_entry, 0);\ else overlay_entry_release_ov(op, (rs)->sr_entry, 0, on) #define RS_FREE_CTRLS(op, rs, on) slap_free_ctrls( op, (rs)->sr_ctrls ) #define RS_FREE_MATCHED(op, rs, on) ch_free( (char *) (rs)->sr_matched ) #define RS_FREE_REF(op, rs, on) ber_bvarray_free( (rs)->sr_ref ) #define RS_FLUSH(MEMBER, op, rs, on, reset, preActions, postActions) do { \ SlapReply *const rfRS = (rs); \ preActions; \ if ( rfRS->sr_flags & REP_##MEMBER##_MUSTFLUSH ) { \ if ( rfRS->SR_##MEMBER ) { \ RS_FREE_##MEMBER( op, rfRS, on ); \ if ( reset ) rfRS->SR_##MEMBER = NULL; \ } \ } \ rfRS->sr_flags &= ~REP_##MEMBER##_MASK; \ postActions; \ } while (0) #define RS_REPLACE(MEMBER, op, rs, on, val, isDup) \ RS_FLUSH( MEMBER, op, rs, on, 0, \ SR_##MEMBER##_t const rfNewval = (val), \ if ( isDup ) rfRS->sr_flags |= REP_##MEMBER##_MUSTBEFREED; \ rfRS->SR_##MEMBER = rfNewval ) /* Warn if something re#defines the following, which would break RS_REPLACE */ #define ENTRY ENTRY #define CTRLS CTRLS #define MATCHED MATCHED #define REF REF