Skip to content

Commit

Permalink
fix recursion bug
Browse files Browse the repository at this point in the history
Previously, linking a field of e.g. a calc record to itself
(calc.INPA = calc.A) directly or through a chain of other records
that support to follow the link for attribures like units, precision
caused an infinite resursion and crashed the ioc.

Also added support for seq link 0 fields which had been added meanwhile.
  • Loading branch information
dirk-zimoch committed Nov 25, 2024
1 parent b7cc33c commit c73ffbe
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 103 deletions.
66 changes: 37 additions & 29 deletions modules/database/src/std/rec/aSubRecord.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,47 +302,55 @@ static long get_outlinkNumber(int fieldIndex) {
return -1;
}

#define do_without_recursion(func, plink, ...) \
do { \
dbScanLock((dbCommon*)prec); \
DBLINK link = *(plink); \
(plink)->lset = NULL; \
func(&link, __VA_ARGS__); \
(plink)->lset = link.lset; \
dbScanUnlock((dbCommon*)prec); \
} while(0)

static long get_units(DBADDR *paddr, char *units)
{
aSubRecord *prec = (aSubRecord *)paddr->precord;
int linkNumber;

linkNumber = get_inlinkNumber(dbGetFieldIndex(paddr));
if (linkNumber >= 0) {
dbGetUnits(&prec->inpa + linkNumber, units, DB_UNITS_SIZE);
do_without_recursion(dbGetUnits, &prec->inpa + linkNumber, units, DB_UNITS_SIZE);
return 0;
}
linkNumber = get_outlinkNumber(dbGetFieldIndex(paddr));
if (linkNumber >= 0) {
dbGetUnits(&prec->outa + linkNumber, units, DB_UNITS_SIZE);
do_without_recursion(dbGetUnits, &prec->outa + linkNumber, units, DB_UNITS_SIZE);
}
return 0;
}

static long get_precision(const DBADDR *paddr, long *pprecision)
{
aSubRecord *prec = (aSubRecord *)paddr->precord;
long status;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
short precision;

*pprecision = prec->prec;
linkNumber = get_inlinkNumber(fieldIndex);
if (linkNumber >= 0) {
short precision;

if (dbGetPrecision(&prec->inpa + linkNumber, &precision) == 0)
*pprecision = precision;
do_without_recursion(status = dbGetPrecision, &prec->inpa + linkNumber, &precision);
if (status == 0) *pprecision = precision;
return 0;
}

linkNumber = get_outlinkNumber(fieldIndex);
if (linkNumber >= 0) {
short precision;

if (dbGetPrecision(&prec->outa + linkNumber, &precision) == 0)
*pprecision = precision;
} else
recGblGetPrec(paddr, pprecision);
do_without_recursion(status = dbGetPrecision, &prec->outa + linkNumber, &precision);
if (status == 0) *pprecision = precision;
return 0;
}
recGblGetPrec(paddr, pprecision);
return 0;
}

Expand All @@ -354,16 +362,16 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)

linkNumber = get_inlinkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
do_without_recursion(dbGetGraphicLimits, &prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
return 0;
}
linkNumber = get_outlinkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->outa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
do_without_recursion(dbGetGraphicLimits, &prec->outa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
}
return 0;
}
Expand All @@ -382,20 +390,20 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)

linkNumber = get_inlinkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
do_without_recursion(dbGetAlarmLimits, &prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
return 0;
}
linkNumber = get_outlinkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->outa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
do_without_recursion(dbGetAlarmLimits, &prec->outa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
return 0;
}
recGblGetAlarmDouble(paddr, pad);
Expand Down
42 changes: 26 additions & 16 deletions modules/database/src/std/rec/calcRecord.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ static long get_linkNumber(int fieldIndex) {
return -1;
}

#define do_without_recursion(func, plink, ...) \
do { \
dbScanLock((dbCommon*)prec); \
DBLINK link = *(plink); \
(plink)->lset = NULL; \
func(&link, __VA_ARGS__); \
(plink)->lset = link.lset; \
dbScanUnlock((dbCommon*)prec); \
} while(0)

static long get_units(DBADDR *paddr, char *units)
{
calcRecord *prec = (calcRecord *)paddr->precord;
Expand All @@ -174,7 +184,7 @@ static long get_units(DBADDR *paddr, char *units)
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
linkNumber = get_linkNumber(dbGetFieldIndex(paddr));
if (linkNumber >= 0)
dbGetUnits(&prec->inpa + linkNumber, units, DB_UNITS_SIZE);
do_without_recursion(dbGetUnits, &prec->inpa + linkNumber, units, DB_UNITS_SIZE);
else
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
Expand All @@ -193,10 +203,10 @@ static long get_precision(const DBADDR *paddr, long *pprecision)

linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
long status;
short precision;

if (dbGetPrecision(&prec->inpa + linkNumber, &precision) == 0)
*pprecision = precision;
do_without_recursion(status = dbGetPrecision, &prec->inpa + linkNumber, &precision);
if (status == 0) *pprecision = precision;
} else
recGblGetPrec(paddr, pprecision);
return 0;
Expand All @@ -222,11 +232,11 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
break;
default:
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
} else
if (linkNumber >= 0)
do_without_recursion(dbGetGraphicLimits, &prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
else
recGblGetGraphicDouble(paddr,pgd);
}
return 0;
Expand Down Expand Up @@ -267,13 +277,13 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
} else {
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
} else
if (linkNumber >= 0)
do_without_recursion(dbGetAlarmLimits, &prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
else
recGblGetAlarmDouble(paddr, pad);
}
return 0;
Expand Down
44 changes: 27 additions & 17 deletions modules/database/src/std/rec/calcoutRecord.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,16 @@ static long get_linkNumber(int fieldIndex) {
return -1;
}

#define do_without_recursion(func, plink, ...) \
do { \
dbScanLock((dbCommon*)prec); \
DBLINK link = *(plink); \
(plink)->lset = NULL; \
func(&link, __VA_ARGS__); \
(plink)->lset = link.lset; \
dbScanUnlock((dbCommon*)prec); \
} while(0)

static long get_units(DBADDR *paddr, char *units)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
Expand All @@ -425,9 +435,9 @@ static long get_units(DBADDR *paddr, char *units)
}

if(paddr->pfldDes->field_type == DBF_DOUBLE) {
linkNumber = get_linkNumber(dbGetFieldIndex(paddr));
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0)
dbGetUnits(&prec->inpa + linkNumber, units, DB_UNITS_SIZE);
do_without_recursion(dbGetUnits, &prec->inpa + linkNumber, units, DB_UNITS_SIZE);
else
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
Expand All @@ -451,10 +461,10 @@ static long get_precision(const DBADDR *paddr, long *pprecision)

linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
long status;
short precision;

if (dbGetPrecision(&prec->inpa + linkNumber, &precision) == 0)
*pprecision = precision;
do_without_recursion(status = dbGetPrecision, &prec->inpa + linkNumber, &precision);
if (status == 0) *pprecision = precision;
} else
recGblGetPrec(paddr, pprecision);
return 0;
Expand Down Expand Up @@ -484,11 +494,11 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
break;
default:
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
} else
if (linkNumber >= 0)
do_without_recursion(dbGetGraphicLimits, &prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
else
recGblGetGraphicDouble(paddr,pgd);
}
return 0;
Expand Down Expand Up @@ -533,13 +543,13 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
} else {
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
} else
if (linkNumber >= 0)
do_without_recursion(dbGetAlarmLimits, &prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
else
recGblGetAlarmDouble(paddr, pad);
}
return 0;
Expand Down
58 changes: 34 additions & 24 deletions modules/database/src/std/rec/seqRecord.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,39 +279,49 @@ static void processCallback(epicsCallback *arg)
#define get_dol(prec, fieldOffset) \
&((linkGrp *) &prec->dly0)[fieldOffset >> 2].dol

#define do_without_recursion(func, plink, ...) \
do { \
dbScanLock((dbCommon*)prec); \
DBLINK link = *(plink); \
(plink)->lset = NULL; \
func(&link, __VA_ARGS__); \
(plink)->lset = link.lset; \
dbScanUnlock((dbCommon*)prec); \
} while(0)

static long get_units(DBADDR *paddr, char *units)
{
seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0);

if (fieldOffset >= 0)
switch (fieldOffset & 2) {
switch (fieldOffset & 3) {
case 0: /* DLYn */
strcpy(units, "s");
break;
case 2: /* DOn */
dbGetUnits(get_dol(prec, fieldOffset),
units, DB_UNITS_SIZE);
}
do_without_recursion(dbGetUnits, get_dol(prec, fieldOffset),
units, DB_UNITS_SIZE);
}
return 0;
}

static long get_precision(const DBADDR *paddr, long *pprecision)
{
seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
long status;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0);
short precision;

if (fieldOffset >= 0)
switch (fieldOffset & 2) {
switch (fieldOffset & 3) {
case 0: /* DLYn */
*pprecision = seqDLYprecision;
return 0;
case 2: /* DOn */
if (dbGetPrecision(get_dol(prec, fieldOffset), &precision) == 0) {
*pprecision = precision;
return 0;
}
do_without_recursion(status = dbGetPrecision, get_dol(prec, fieldOffset), &precision);
if (status == 0) *pprecision = precision;
return 0;
}
*pprecision = prec->prec;
recGblGetPrec(paddr, pprecision);
Expand All @@ -321,18 +331,18 @@ static long get_precision(const DBADDR *paddr, long *pprecision)
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0);

if (fieldOffset >= 0)
switch (fieldOffset & 2) {
switch (fieldOffset & 3) {
case 0: /* DLYn */
pgd->lower_disp_limit = 0.0;
pgd->lower_disp_limit = 10.0;
pgd->upper_disp_limit = 10.0;
return 0;
case 2: /* DOn */
dbGetGraphicLimits(get_dol(prec, fieldOffset),
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
do_without_recursion(dbGetGraphicLimits, get_dol(prec, fieldOffset),
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
return 0;
}
recGblGetGraphicDouble(paddr, pgd);
Expand All @@ -341,9 +351,9 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)

static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0);

if (fieldOffset >= 0 && (fieldOffset & 2) == 0) { /* DLYn */
if (fieldOffset >= 0 && (fieldOffset & 3) == 0) { /* DLYn */
pcd->lower_ctrl_limit = 0.0;
pcd->upper_ctrl_limit = seqDLYlimit;
}
Expand All @@ -355,12 +365,12 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1);
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0);

if (fieldOffset >= 0 && (fieldOffset & 2) == 2) /* DOn */
dbGetAlarmLimits(get_dol(prec, fieldOffset),
&pad->lower_alarm_limit, &pad->lower_warning_limit,
&pad->upper_warning_limit, &pad->upper_alarm_limit);
if (fieldOffset >= 0 && (fieldOffset & 3) == 2) /* DOn */
do_without_recursion(dbGetAlarmLimits, get_dol(prec, fieldOffset),
&pad->lower_alarm_limit, &pad->lower_warning_limit,
&pad->upper_warning_limit, &pad->upper_alarm_limit);
else
recGblGetAlarmDouble(paddr, pad);
return 0;
Expand Down
Loading

0 comments on commit c73ffbe

Please sign in to comment.