[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: (ITS#5340) REP_ENTRY_MODIFIABLE bug in dynlist



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