Better refcount locking to avoid use after free
Under some conditions it could be happen that on a freeing capi object a other thread still get a reference and then it use the already freed object. To avoid this, we do 2 things, we only take a refernce if get_obj() succeed, it do not longer succeed if the object is already cleaned. We also force scheduling after releaseing the lock before really freeing the object - so the waiting thread will not get a new reference.
This commit is contained in:
parent
d9a97bb810
commit
fc757c58dc
|
@ -103,8 +103,12 @@ int register_lController(struct mApplication *appl, struct lController *lc)
|
||||||
eprint("%s: controller idx %d ID:%d\already registered\n", CAPIobjIDstr(&appl->cobj), i, lc->cobj.id);
|
eprint("%s: controller idx %d ID:%d\already registered\n", CAPIobjIDstr(&appl->cobj), i, lc->cobj.id);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
if (get_cobj(&lc->cobj)) {
|
||||||
appl->lcl[i] = lc;
|
appl->lcl[i] = lc;
|
||||||
get_cobj(&lc->cobj);
|
} else {
|
||||||
|
eprint("%s: controller idx %d cannot get controller object %s\n", CAPIobjIDstr(&appl->cobj), i, CAPIobjIDstr(&lc->cobj));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,8 +294,12 @@ struct lController *get_lController(struct mApplication *appl, unsigned int cont
|
||||||
wprint("%s: wrong controller id %d (max %d)\n", CAPIobjIDstr(&appl->cobj), cont, mI_ControllerCount);
|
wprint("%s: wrong controller id %d (max %d)\n", CAPIobjIDstr(&appl->cobj), cont, mI_ControllerCount);
|
||||||
lc = NULL;
|
lc = NULL;
|
||||||
}
|
}
|
||||||
if (lc)
|
if (lc) {
|
||||||
get_cobj(&lc->cobj);
|
if (!get_cobj(&lc->cobj)) {
|
||||||
|
wprint("%s: cannot get controller object %s\n", CAPIobjIDstr(&appl->cobj), CAPIobjIDstr(&lc->cobj));
|
||||||
|
lc = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
return lc;
|
return lc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,7 @@ void CAPIobj_exit(void)
|
||||||
while (co) {
|
while (co) {
|
||||||
cn = co->nextD;
|
cn = co->nextD;
|
||||||
eprint("%s: uid=%i refcnt %d in dangling list - freeing now\n", CAPIobjIDstr(co), co->uid, co->refcnt);
|
eprint("%s: uid=%i refcnt %d in dangling list - freeing now\n", CAPIobjIDstr(co), co->uid, co->refcnt);
|
||||||
|
co->cleaned = 1;
|
||||||
cobj_free(co);
|
cobj_free(co);
|
||||||
co = cn;
|
co = cn;
|
||||||
}
|
}
|
||||||
|
@ -357,9 +358,12 @@ struct mCAPIobj *__get_cobj(struct mCAPIobj *co, const char *file, int lineno)
|
||||||
struct mCAPIobj *get_cobj(struct mCAPIobj *co)
|
struct mCAPIobj *get_cobj(struct mCAPIobj *co)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
struct mCAPIobj *p;
|
||||||
|
|
||||||
if (co) {
|
if (co) {
|
||||||
if (co->parent) {
|
p = co->parent;
|
||||||
pthread_rwlock_wrlock(&co->parent->lock);
|
if (p) {
|
||||||
|
pthread_rwlock_wrlock(&p->lock);
|
||||||
} else {
|
} else {
|
||||||
if (co->type != Cot_Root) { /* has no parent */
|
if (co->type != Cot_Root) { /* has no parent */
|
||||||
cobj_err("%s: parent not assigned\n", CAPIobjIDstr(co));
|
cobj_err("%s: parent not assigned\n", CAPIobjIDstr(co));
|
||||||
|
@ -367,12 +371,17 @@ struct mCAPIobj *get_cobj(struct mCAPIobj *co)
|
||||||
}
|
}
|
||||||
pthread_mutex_lock(&rootLock);
|
pthread_mutex_lock(&rootLock);
|
||||||
}
|
}
|
||||||
|
if (co->cleaned) {
|
||||||
|
cobj_warn("%s: pending free detected - do not get object\n", CAPIobjIDstr(co));
|
||||||
|
co = NULL;
|
||||||
|
} else {
|
||||||
if (co->freeing)
|
if (co->freeing)
|
||||||
cobj_err("Currently freeing %s refcnt: %d\n", CAPIobjIDstr(co), co->refcnt);
|
cobj_err("Currently freeing %s refcnt: %d\n", CAPIobjIDstr(co), co->refcnt);
|
||||||
co->refcnt++;
|
co->refcnt++;
|
||||||
coref_dbg("%s\n", CAPIobjIDstr(co));
|
coref_dbg("%s\n", CAPIobjIDstr(co));
|
||||||
if (co->parent)
|
}
|
||||||
pthread_rwlock_unlock(&co->parent->lock);
|
if (p)
|
||||||
|
pthread_rwlock_unlock(&p->lock);
|
||||||
else
|
else
|
||||||
pthread_mutex_unlock(&rootLock);
|
pthread_mutex_unlock(&rootLock);
|
||||||
} else
|
} else
|
||||||
|
@ -403,6 +412,10 @@ int put_cobj(struct mCAPIobj *co)
|
||||||
ret = co->refcnt;
|
ret = co->refcnt;
|
||||||
if (co->cleaned && co->refcnt <= 0) { /* last ref */
|
if (co->cleaned && co->refcnt <= 0) { /* last ref */
|
||||||
pthread_rwlock_unlock(&p->lock);
|
pthread_rwlock_unlock(&p->lock);
|
||||||
|
/* OK not perfect but scheduling here should prevent us from access of freed memory, if a other thread
|
||||||
|
still pending on the lock - a cleaned object is not longer listed and do not return success in get_obj()
|
||||||
|
so getting a new reference should not happen after this point */
|
||||||
|
sched_yield();
|
||||||
cobj_free(co);
|
cobj_free(co);
|
||||||
} else {
|
} else {
|
||||||
pthread_rwlock_unlock(&p->lock);
|
pthread_rwlock_unlock(&p->lock);
|
||||||
|
@ -447,9 +460,14 @@ struct mCAPIobj *get_next_cobj(struct mCAPIobj *parent, struct mCAPIobj *cur)
|
||||||
else
|
else
|
||||||
next = parent->listhead;
|
next = parent->listhead;
|
||||||
if (next) {
|
if (next) {
|
||||||
|
if (next->cleaned) {
|
||||||
|
cobj_warn("%s: pending free detected - do not get next\n", CAPIobjIDstr(next));
|
||||||
|
next = NULL;
|
||||||
|
} else {
|
||||||
next->refcnt++;
|
next->refcnt++;
|
||||||
coref_dbg("%s: next %s\n", CAPIobjIDstr(cur), CAPIobjIDstr(next));
|
coref_dbg("%s: next %s\n", CAPIobjIDstr(cur), CAPIobjIDstr(next));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pthread_rwlock_unlock(&parent->lock);
|
pthread_rwlock_unlock(&parent->lock);
|
||||||
if (parent->freeing)
|
if (parent->freeing)
|
||||||
cobj_err("Currently freeing %s refcnt: %d Next: %s\n", CAPIobjIDstr(parent), parent->refcnt, CAPIobjIDstr(next));
|
cobj_err("Currently freeing %s refcnt: %d Next: %s\n", CAPIobjIDstr(parent), parent->refcnt, CAPIobjIDstr(next));
|
||||||
|
|
|
@ -1141,6 +1141,16 @@ int OpenBInstance(struct BInstance *bi, struct lPLCI *lp)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (get_cobj(&lp->cobj)) {
|
||||||
|
bi->lp = lp;
|
||||||
|
} else {
|
||||||
|
bi->lp = NULL;
|
||||||
|
ret = -EINVAL;
|
||||||
|
wprint("Cannot get logical controller object\n");
|
||||||
|
close(sk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
switch (lp->btype) {
|
switch (lp->btype) {
|
||||||
case BType_Direct:
|
case BType_Direct:
|
||||||
bi->from_down = recvBdirect;
|
bi->from_down = recvBdirect;
|
||||||
|
@ -1160,6 +1170,8 @@ int OpenBInstance(struct BInstance *bi, struct lPLCI *lp)
|
||||||
eprint("Error unnkown BType %d\n", lp->btype);
|
eprint("Error unnkown BType %d\n", lp->btype);
|
||||||
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
||||||
close(sk);
|
close(sk);
|
||||||
|
bi->lp = NULL;
|
||||||
|
put_cobj(&lp->cobj);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
bi->type = lp->btype;
|
bi->type = lp->btype;
|
||||||
|
@ -1181,11 +1193,11 @@ int OpenBInstance(struct BInstance *bi, struct lPLCI *lp)
|
||||||
bi->from_down = dummy_btrans;
|
bi->from_down = dummy_btrans;
|
||||||
bi->from_up = dummy_btrans;
|
bi->from_up = dummy_btrans;
|
||||||
bi->type = BType_None;
|
bi->type = BType_None;
|
||||||
|
bi->lp = NULL;
|
||||||
|
put_cobj(&lp->cobj);
|
||||||
} else {
|
} else {
|
||||||
bi->closed = 0;
|
bi->closed = 0;
|
||||||
bi->fd = sk;
|
bi->fd = sk;
|
||||||
bi->lp = lp;
|
|
||||||
get_cobj(&lp->cobj);
|
|
||||||
bi->org_rx_min = MISDN_CTRL_RX_SIZE_IGNORE;
|
bi->org_rx_min = MISDN_CTRL_RX_SIZE_IGNORE;
|
||||||
bi->rx_min = MISDN_CTRL_RX_SIZE_IGNORE;
|
bi->rx_min = MISDN_CTRL_RX_SIZE_IGNORE;
|
||||||
bi->org_rx_max = MISDN_CTRL_RX_SIZE_IGNORE;
|
bi->org_rx_max = MISDN_CTRL_RX_SIZE_IGNORE;
|
||||||
|
@ -1243,8 +1255,8 @@ int OpenBInstance(struct BInstance *bi, struct lPLCI *lp)
|
||||||
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
||||||
close(sk);
|
close(sk);
|
||||||
bi->fd = -1;
|
bi->fd = -1;
|
||||||
put_cobj(&lp->cobj);
|
|
||||||
bi->lp = NULL;
|
bi->lp = NULL;
|
||||||
|
put_cobj(&lp->cobj);
|
||||||
} else {
|
} else {
|
||||||
dprint(MIDEBUG_CONTROLLER, "Controller%d: Bchannel %d socket %d added to poll idx %d\n",
|
dprint(MIDEBUG_CONTROLLER, "Controller%d: Bchannel %d socket %d added to poll idx %d\n",
|
||||||
bi->pc->profile.ncontroller, bi->nr, sk, ret);
|
bi->pc->profile.ncontroller, bi->nr, sk, ret);
|
||||||
|
@ -1260,8 +1272,8 @@ int OpenBInstance(struct BInstance *bi, struct lPLCI *lp)
|
||||||
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
||||||
close(sk);
|
close(sk);
|
||||||
bi->fd = -1;
|
bi->fd = -1;
|
||||||
put_cobj(&lp->cobj);
|
|
||||||
bi->lp = NULL;
|
bi->lp = NULL;
|
||||||
|
put_cobj(&lp->cobj);
|
||||||
} else {
|
} else {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
bi->UpId = 0;
|
bi->UpId = 0;
|
||||||
|
@ -1274,8 +1286,8 @@ int OpenBInstance(struct BInstance *bi, struct lPLCI *lp)
|
||||||
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
||||||
close(sk);
|
close(sk);
|
||||||
bi->fd = -1;
|
bi->fd = -1;
|
||||||
put_cobj(&lp->cobj);
|
|
||||||
bi->lp = NULL;
|
bi->lp = NULL;
|
||||||
|
put_cobj(&lp->cobj);
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
bi->pfd[2].fd = bi->tty;
|
bi->pfd[2].fd = bi->tty;
|
||||||
|
@ -1287,8 +1299,8 @@ int OpenBInstance(struct BInstance *bi, struct lPLCI *lp)
|
||||||
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
dprint(MIDEBUG_CONTROLLER, "close socket bi[%d]->fd %d\n", bi->nr, sk);
|
||||||
close(sk);
|
close(sk);
|
||||||
bi->fd = -1;
|
bi->fd = -1;
|
||||||
put_cobj(&lp->cobj);
|
|
||||||
bi->lp = NULL;
|
bi->lp = NULL;
|
||||||
|
put_cobj(&lp->cobj);
|
||||||
} else {
|
} else {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
bi->UpId = 0;
|
bi->UpId = 0;
|
||||||
|
|
|
@ -128,14 +128,19 @@ struct lController *addlController(struct mApplication *app, struct pController
|
||||||
lc = calloc(1, sizeof(*lc));
|
lc = calloc(1, sizeof(*lc));
|
||||||
if (lc) {
|
if (lc) {
|
||||||
lc->cobj.id2 = app->cobj.id2;
|
lc->cobj.id2 = app->cobj.id2;
|
||||||
|
if (!get_cobj(&app->cobj)) {
|
||||||
|
eprint("Cannot get application object\n");
|
||||||
|
free(lc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
ret = init_cobj_registered(&lc->cobj, &pc->cobjLC, Cot_lController, 0x0000ff);
|
ret = init_cobj_registered(&lc->cobj, &pc->cobjLC, Cot_lController, 0x0000ff);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
eprint("Controller%d: Application %d - cannot init\n", pc->profile.ncontroller, app->cobj.id2);
|
eprint("Controller%d: Application %d - cannot init\n", pc->profile.ncontroller, app->cobj.id2);
|
||||||
|
put_cobj(&app->cobj);
|
||||||
free(lc);
|
free(lc);
|
||||||
lc = NULL;
|
lc = NULL;
|
||||||
} else {
|
} else {
|
||||||
lc->Appl = app;
|
lc->Appl = app;
|
||||||
get_cobj(&app->cobj);
|
|
||||||
lc->listen_m.fsm = &listen_fsm;
|
lc->listen_m.fsm = &listen_fsm;
|
||||||
lc->listen_m.state = ST_LISTEN_L_0;
|
lc->listen_m.state = ST_LISTEN_L_0;
|
||||||
lc->listen_m.debug = MIDEBUG_CONTROLLER & mI_debug_mask;
|
lc->listen_m.debug = MIDEBUG_CONTROLLER & mI_debug_mask;
|
||||||
|
@ -146,10 +151,13 @@ struct lController *addlController(struct mApplication *app, struct pController
|
||||||
lc->CIPmask2 = 0;
|
lc->CIPmask2 = 0;
|
||||||
ret = register_lController(app, lc);
|
ret = register_lController(app, lc);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
lc->Appl = NULL;
|
||||||
put_cobj(&app->cobj);
|
put_cobj(&app->cobj);
|
||||||
eprint("Controller%d: - cannot register LC on Application %d - %s\n", pc->profile.ncontroller,
|
eprint("Controller%d: - cannot register LC on Application %d - %s\n", pc->profile.ncontroller,
|
||||||
app->cobj.id2, strerror(-ret));
|
app->cobj.id2, strerror(-ret));
|
||||||
free(lc);
|
lc->cobj.cleaned = 1;
|
||||||
|
delist_cobj(&lc->cobj);
|
||||||
|
put_cobj(&lc->cobj);
|
||||||
lc = NULL;
|
lc = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1747,10 +1747,24 @@ int lPLCICreate(struct lPLCI **lpp, struct lController *lc, struct mPLCI *plci,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
lp->cipmask = cipmask;
|
lp->cipmask = cipmask;
|
||||||
|
if (get_cobj(&lc->cobj)) {
|
||||||
lp->lc = lc;
|
lp->lc = lc;
|
||||||
get_cobj(&lc->cobj);
|
} else {
|
||||||
|
wprint("%s: Cannot get lController object\n", CAPIobjIDstr(&lc->cobj));
|
||||||
|
lp->cobj.cleaned = 1;
|
||||||
|
delist_cobj(&lp->cobj);
|
||||||
|
put_cobj(&lp->cobj); /* will cleanup and free too */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (get_cobj(&lc->Appl->cobj)) {
|
||||||
lp->Appl = lc->Appl;
|
lp->Appl = lc->Appl;
|
||||||
get_cobj(&lc->Appl->cobj);
|
} else {
|
||||||
|
wprint("%s: Cannot get application object\n", CAPIobjIDstr(&lc->Appl->cobj));
|
||||||
|
lp->cobj.cleaned = 1;
|
||||||
|
delist_cobj(&lp->cobj);
|
||||||
|
put_cobj(&lp->cobj); /* will cleanup and free too */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
if (plci->pc->profile.goptions & 0x0008) {
|
if (plci->pc->profile.goptions & 0x0008) {
|
||||||
/* DTMF */
|
/* DTMF */
|
||||||
lp->l1dtmf = 1;
|
lp->l1dtmf = 1;
|
||||||
|
@ -1762,8 +1776,15 @@ int lPLCICreate(struct lPLCI **lpp, struct lController *lc, struct mPLCI *plci,
|
||||||
lp->plci_m.printdebug = lPLCI_debug;
|
lp->plci_m.printdebug = lPLCI_debug;
|
||||||
lp->chid.nr = MI_CHAN_NONE;
|
lp->chid.nr = MI_CHAN_NONE;
|
||||||
lp->autohangup = 1;
|
lp->autohangup = 1;
|
||||||
|
if (get_cobj(&lp->cobj)) { /* timer ref */
|
||||||
init_timer(&lp->atimer, mICAPItimer_base, lp, atimer_timeout);
|
init_timer(&lp->atimer, mICAPItimer_base, lp, atimer_timeout);
|
||||||
get_cobj(&lp->cobj); /* timer ref */
|
} else {
|
||||||
|
wprint("%s: Cannot get lplci object for timer ref\n", CAPIobjIDstr(&lp->cobj));
|
||||||
|
lp->cobj.cleaned = 1;
|
||||||
|
delist_cobj(&lp->cobj);
|
||||||
|
put_cobj(&lp->cobj); /* will cleanup and free too */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
*lpp = lp;
|
*lpp = lp;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,19 +133,26 @@ struct mCAPIobj {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if __GNUC_PREREQ (3,4)
|
||||||
|
# define __WUR __attribute__ ((__warn_unused_result__))
|
||||||
|
#else
|
||||||
|
# define __WUR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
|
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
|
||||||
struct mCAPIobj *__get_cobj(struct mCAPIobj *, const char *, int);
|
struct mCAPIobj *__get_cobj(struct mCAPIobj *, const char *, int) __WUR;
|
||||||
int __put_cobj(struct mCAPIobj *, const char *, int);
|
int __put_cobj(struct mCAPIobj *, const char *, int);
|
||||||
struct mCAPIobj *__get_next_cobj(struct mCAPIobj *, struct mCAPIobj *, const char *, int);
|
struct mCAPIobj *__get_next_cobj(struct mCAPIobj *, struct mCAPIobj *, const char *, int) __WUR;
|
||||||
int __delist_cobj(struct mCAPIobj *, const char *, int);
|
int __delist_cobj(struct mCAPIobj *, const char *, int);
|
||||||
#define get_cobj(co) __get_cobj(co, __FILE__, __LINE__)
|
#define get_cobj(co) __get_cobj(co, __FILE__, __LINE__)
|
||||||
#define put_cobj(co) __put_cobj(co, __FILE__, __LINE__)
|
#define put_cobj(co) __put_cobj(co, __FILE__, __LINE__)
|
||||||
#define get_next_cobj(pa, co) __get_next_cobj(pa, co, __FILE__, __LINE__)
|
#define get_next_cobj(pa, co) __get_next_cobj(pa, co, __FILE__, __LINE__)
|
||||||
#define delist_cobj(co) __delist_cobj(co, __FILE__, __LINE__)
|
#define delist_cobj(co) __delist_cobj(co, __FILE__, __LINE__)
|
||||||
#else
|
#else
|
||||||
struct mCAPIobj *get_cobj(struct mCAPIobj *);
|
struct mCAPIobj *get_cobj(struct mCAPIobj *) __WUR;
|
||||||
int put_cobj(struct mCAPIobj *);
|
int put_cobj(struct mCAPIobj *);
|
||||||
struct mCAPIobj *get_next_cobj(struct mCAPIobj *, struct mCAPIobj *);
|
struct mCAPIobj *get_next_cobj(struct mCAPIobj *, struct mCAPIobj *) __WUR;
|
||||||
int delist_cobj(struct mCAPIobj *);
|
int delist_cobj(struct mCAPIobj *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -640,6 +640,7 @@ struct mNCCI *ncciCreate(struct lPLCI *lp)
|
||||||
{
|
{
|
||||||
struct mNCCI *nc;
|
struct mNCCI *nc;
|
||||||
int err;
|
int err;
|
||||||
|
struct mApplication *appl = NULL;
|
||||||
|
|
||||||
nc = calloc(1, sizeof(*nc));
|
nc = calloc(1, sizeof(*nc));
|
||||||
if (!nc) {
|
if (!nc) {
|
||||||
|
@ -647,6 +648,15 @@ struct mNCCI *ncciCreate(struct lPLCI *lp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
nc->cobj.id2 = lp->cobj.id2;
|
nc->cobj.id2 = lp->cobj.id2;
|
||||||
|
if (lp->Appl) {
|
||||||
|
if (get_cobj(&lp->Appl->cobj)) {
|
||||||
|
appl = lp->Appl;
|
||||||
|
} else {
|
||||||
|
wprint("Cannot get application object\n");
|
||||||
|
free(nc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
err = init_cobj_registered(&nc->cobj, &lp->cobj, Cot_NCCI, 0x01ffff);
|
err = init_cobj_registered(&nc->cobj, &lp->cobj, Cot_NCCI, 0x01ffff);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
dprint(MIDEBUG_NCCI, "NCCI%06x: will be created now\n", nc->cobj.id);
|
dprint(MIDEBUG_NCCI, "NCCI%06x: will be created now\n", nc->cobj.id);
|
||||||
|
@ -654,9 +664,7 @@ struct mNCCI *ncciCreate(struct lPLCI *lp)
|
||||||
nc->ncci_m.debug = MIDEBUG_NCCI & mI_debug_mask;
|
nc->ncci_m.debug = MIDEBUG_NCCI & mI_debug_mask;
|
||||||
nc->ncci_m.userdata = nc;
|
nc->ncci_m.userdata = nc;
|
||||||
nc->ncci_m.printdebug = ncci_debug;
|
nc->ncci_m.printdebug = ncci_debug;
|
||||||
nc->appl = lp->Appl;
|
nc->appl = appl;
|
||||||
if (nc->appl)
|
|
||||||
get_cobj(&nc->appl->cobj);
|
|
||||||
nc->BIlink = lp->BIlink;
|
nc->BIlink = lp->BIlink;
|
||||||
nc->window = lp->Appl->MaxB3Blk;
|
nc->window = lp->Appl->MaxB3Blk;
|
||||||
pthread_mutex_init(&nc->lock, NULL);
|
pthread_mutex_init(&nc->lock, NULL);
|
||||||
|
@ -710,6 +718,8 @@ struct mNCCI *ncciCreate(struct lPLCI *lp)
|
||||||
nc->osize = 256;
|
nc->osize = 256;
|
||||||
dprint(MIDEBUG_NCCI, "%s: created\n", CAPIobjIDstr(&nc->cobj));
|
dprint(MIDEBUG_NCCI, "%s: created\n", CAPIobjIDstr(&nc->cobj));
|
||||||
} else {
|
} else {
|
||||||
|
if (appl)
|
||||||
|
put_cobj(&appl->cobj);
|
||||||
free(nc);
|
free(nc);
|
||||||
nc = NULL;
|
nc = NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue