Merge remote-tracking branch 'github/recursion_bug_v2' into PSI-7.0

This commit is contained in:
2024-12-05 16:59:12 +01:00
3 changed files with 43 additions and 40 deletions

View File

@ -232,19 +232,41 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
return status; return status;
} }
/* Some records get options (precsision, units, ...) for some fields
* from an input link. We need to catch the case that this link
* points back to the same field or we will end in an infinite recursion.
*/
static long dbDbGetOptionLoopSafe(const struct link *plink, short dbrType,
void *pbuffer, long option)
{
/* We need to cast away const to set the flags.
That's ok because we know that plink is never actually readonly.
And we reset everything to its original state.
*/
struct link *mutable_plink = (struct link *)plink;
long status = S_dbLib_badLink;
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
long number_elements = 0;
dbScanLock(paddr->precord);
if (!(mutable_plink->flags & DBLINK_FLAG_VISITED)) {
mutable_plink->flags |= DBLINK_FLAG_VISITED;
status = dbGet(paddr, dbrType, pbuffer, &option, &number_elements, NULL);
mutable_plink->flags &= ~DBLINK_FLAG_VISITED;
}
dbScanUnlock(paddr->precord);
return status;
}
static long dbDbGetControlLimits(const struct link *plink, double *low, static long dbDbGetControlLimits(const struct link *plink, double *low,
double *high) double *high)
{ {
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
struct buffer { struct buffer {
DBRctrlDouble DBRctrlDouble
double value; double value;
} buffer; } buffer;
long options = DBR_CTRL_DOUBLE; long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_CTRL_DOUBLE);
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
NULL);
if (status) if (status)
return status; return status;
@ -257,16 +279,11 @@ static long dbDbGetControlLimits(const struct link *plink, double *low,
static long dbDbGetGraphicLimits(const struct link *plink, double *low, static long dbDbGetGraphicLimits(const struct link *plink, double *low,
double *high) double *high)
{ {
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
struct buffer { struct buffer {
DBRgrDouble DBRgrDouble
double value; double value;
} buffer; } buffer;
long options = DBR_GR_DOUBLE; long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_GR_DOUBLE);
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
NULL);
if (status) if (status)
return status; return status;
@ -279,16 +296,11 @@ static long dbDbGetGraphicLimits(const struct link *plink, double *low,
static long dbDbGetAlarmLimits(const struct link *plink, double *lolo, static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
double *low, double *high, double *hihi) double *low, double *high, double *hihi)
{ {
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
struct buffer { struct buffer {
DBRalDouble DBRalDouble
double value; double value;
} buffer; } buffer;
long options = DBR_AL_DOUBLE; long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_AL_DOUBLE);
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
0);
if (status) if (status)
return status; return status;
@ -302,16 +314,11 @@ static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
static long dbDbGetPrecision(const struct link *plink, short *precision) static long dbDbGetPrecision(const struct link *plink, short *precision)
{ {
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
struct buffer { struct buffer {
DBRprecision DBRprecision
double value; double value;
} buffer; } buffer;
long options = DBR_PRECISION; long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_PRECISION);
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
0);
if (status) if (status)
return status; return status;
@ -322,16 +329,11 @@ static long dbDbGetPrecision(const struct link *plink, short *precision)
static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize) static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
{ {
dbChannel *chan = linkChannel(plink);
DBADDR *paddr = &chan->addr;
struct buffer { struct buffer {
DBRunits DBRunits
double value; double value;
} buffer; } buffer;
long options = DBR_UNITS; long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_UNITS);
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
0);
if (status) if (status)
return status; return status;

View File

@ -72,6 +72,7 @@ DBCORE_API extern const maplinkType pamaplinkType[LINK_NTYPES];
/* DBLINK Flag bits */ /* DBLINK Flag bits */
#define DBLINK_FLAG_INITIALIZED 1 /* dbInitLink() called */ #define DBLINK_FLAG_INITIALIZED 1 /* dbInitLink() called */
#define DBLINK_FLAG_TSELisTIME 2 /* Use TSEL to get timeStamp */ #define DBLINK_FLAG_TSELisTIME 2 /* Use TSEL to get timeStamp */
#define DBLINK_FLAG_VISITED 4 /* Used in loop detection */
struct macro_link { struct macro_link {
char *macroStr; char *macroStr;

View File

@ -282,10 +282,10 @@ static void processCallback(epicsCallback *arg)
static long get_units(DBADDR *paddr, char *units) static long get_units(DBADDR *paddr, char *units)
{ {
seqRecord *prec = (seqRecord *) paddr->precord; seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1); int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0);
if (fieldOffset >= 0) if (fieldOffset >= 0)
switch (fieldOffset & 2) { switch (fieldOffset & 3) {
case 0: /* DLYn */ case 0: /* DLYn */
strcpy(units, "s"); strcpy(units, "s");
break; break;
@ -299,11 +299,11 @@ static long get_units(DBADDR *paddr, char *units)
static long get_precision(const DBADDR *paddr, long *pprecision) static long get_precision(const DBADDR *paddr, long *pprecision)
{ {
seqRecord *prec = (seqRecord *) paddr->precord; seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1); int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0);
short precision; short precision;
if (fieldOffset >= 0) if (fieldOffset >= 0)
switch (fieldOffset & 2) { switch (fieldOffset & 3) {
case 0: /* DLYn */ case 0: /* DLYn */
*pprecision = seqDLYprecision; *pprecision = seqDLYprecision;
return 0; return 0;
@ -321,10 +321,10 @@ static long get_precision(const DBADDR *paddr, long *pprecision)
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd) static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{ {
seqRecord *prec = (seqRecord *) paddr->precord; seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1); int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0);
if (fieldOffset >= 0) if (fieldOffset >= 0)
switch (fieldOffset & 2) { switch (fieldOffset & 3) {
case 0: /* DLYn */ case 0: /* DLYn */
pgd->lower_disp_limit = 0.0; pgd->lower_disp_limit = 0.0;
pgd->lower_disp_limit = 10.0; pgd->lower_disp_limit = 10.0;
@ -341,9 +341,9 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd) 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->lower_ctrl_limit = 0.0;
pcd->upper_ctrl_limit = seqDLYlimit; pcd->upper_ctrl_limit = seqDLYlimit;
} }
@ -355,9 +355,9 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad) static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{ {
seqRecord *prec = (seqRecord *) paddr->precord; seqRecord *prec = (seqRecord *) paddr->precord;
int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1); int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0);
if (fieldOffset >= 0 && (fieldOffset & 2) == 2) /* DOn */ if (fieldOffset >= 0 && (fieldOffset & 3) == 2) /* DOn */
dbGetAlarmLimits(get_dol(prec, fieldOffset), dbGetAlarmLimits(get_dol(prec, fieldOffset),
&pad->lower_alarm_limit, &pad->lower_warning_limit, &pad->lower_alarm_limit, &pad->lower_warning_limit,
&pad->upper_warning_limit, &pad->upper_alarm_limit); &pad->upper_warning_limit, &pad->upper_alarm_limit);