Planner: Fix Warning from Coverity.

Fix an interger overflow warning when parsing setpoints.

@bstoeger: In the end it turned out that this parser was only used in
one place in the planner UI, and it was simplest to switch this to
using `QVariant.toFloat()` in the model itself, which is consistent how
the rest of the input values is parsed and validated.

Signed-off-by: Michael Keller <github@ike.ch>
This commit is contained in:
Michael Keller 2024-09-02 20:42:47 +12:00
parent cc55c442a3
commit 33bb39f1ca
3 changed files with 22 additions and 148 deletions

View file

@ -1102,131 +1102,3 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
return decodive; return decodive;
} }
/*
* Get a value with a given number of decimals:
* - get_decimals("10.2", &"10.2", 1) == 102
* - get_decimals("9", &"9", 1) = 90
* - get_decimals("1.35", &"1.35", 2) == 135))
*
* Return negative for errors.
*/
static int get_decimals(const char *begin, const char **endp, const unsigned decimals)
{
char *end;
int value = strtol(begin, &end, 10);
if (begin == end)
return -1;
/* Fraction? We only look at the first digit */
if (*end == '.')
end++;
unsigned fraction = 0;
for (unsigned i = 0; i < decimals; i++) {
value *= 10;
unsigned digit = 0;
if (isdigit(*end)) {
digit = *end - '0';
end++;
} else if (*end != '\0') {
return -1;
}
fraction = 10 * fraction + digit;
}
value += fraction;
do {
end++;
} while (isdigit(*end));
*endp = end;
return value;
}
static int get_permille(const char *begin, const char **end)
{
int value = get_decimals(begin, end, 1);
if (value >= 0) {
/* Allow a percentage sign */
if (**end == '%')
++*end;
}
return value;
}
int validate_gas(const char *text, struct gasmix *gas)
{
int o2, he;
if (!text)
return 0;
while (isspace(*text))
text++;
if (!*text)
return 0;
if (!strcasecmp(text, translate("gettextFromC", "air"))) {
o2 = O2_IN_AIR;
he = 0;
text += strlen(translate("gettextFromC", "air"));
} else if (!strcasecmp(text, translate("gettextFromC", "oxygen"))) {
o2 = 1000;
he = 0;
text += strlen(translate("gettextFromC", "oxygen"));
} else if (!strncasecmp(text, translate("gettextFromC", "ean"), 3)) {
o2 = get_permille(text + 3, &text);
he = 0;
} else {
o2 = get_permille(text, &text);
he = 0;
if (*text == '/')
he = get_permille(text + 1, &text);
}
/* We don't want any extra crud */
while (isspace(*text))
text++;
if (*text)
return 0;
/* Validate the gas mix */
if (*text || o2 < 1 || o2 > 1000 || he < 0 || o2 + he > 1000)
return 0;
/* Let it rip */
gas->o2.permille = o2;
gas->he.permille = he;
return 1;
}
int validate_po2(const char *text, int *mbar_po2)
{
int po2;
if (!text)
return 0;
po2 = get_decimals(text, &text, 2);
if (po2 < 0)
return 0;
while (isspace(*text))
text++;
if (*text)
return 0;
*mbar_po2 = po2 * 10;
if (*mbar_po2 < 160)
*mbar_po2 = 160;
return 1;
}

View file

@ -40,8 +40,6 @@ typedef enum {
PLAN_ERROR_INAPPROPRIATE_GAS, PLAN_ERROR_INAPPROPRIATE_GAS,
} planner_error_t; } planner_error_t;
extern int validate_gas(const char *text, struct gasmix *gas);
extern int validate_po2(const char *text, int *mbar_po2);
extern int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_t time); extern int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_t time);
extern bool diveplan_empty(struct diveplan *diveplan); extern bool diveplan_empty(struct diveplan *diveplan);
extern void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_disclaimer, planner_error_t error); extern void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_disclaimer, planner_error_t error);

View file

@ -357,13 +357,15 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
if (role == Qt::EditRole) { if (role == Qt::EditRole) {
divedatapoint &p = divepoints[index.row()]; divedatapoint &p = divepoints[index.row()];
switch (index.column()) { switch (index.column()) {
case DEPTH: case DEPTH: {
if (value.toInt() >= 0) { int depth = value.toInt();
p.depth = units_to_depth(value.toInt()); if (depth >= 0) {
p.depth = units_to_depth(depth);
if (updateMaxDepth()) if (updateMaxDepth())
cylinders.updateBestMixes(); cylinders.updateBestMixes();
} }
break; break;
}
case RUNTIME: { case RUNTIME: {
int secs = value.toInt() * 60; int secs = value.toInt() * 60;
i = index.row(); i = index.row();
@ -381,7 +383,7 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
} }
case DURATION: { case DURATION: {
int secs = value.toInt() * 60; int secs = value.toInt() * 60;
if (!secs) if (secs < 0)
secs = 10; secs = 10;
i = index.row(); i = index.row();
if (i) if (i)
@ -393,10 +395,12 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
break; break;
} }
case CCSETPOINT: { case CCSETPOINT: {
int po2 = 0; bool ok;
QByteArray gasv = value.toByteArray(); int po2 = round(value.toFloat(&ok) * 100) * 10;
if (validate_po2(gasv.data(), &po2))
p.setpoint = po2; if (ok)
p.setpoint = std::max(po2, 160);
break; break;
} }
case GAS: case GAS: