common: validate and properly parse floats

Fixes: #1665.
This commit is contained in:
Andrew J. Hesford 2024-03-27 22:13:50 -04:00
parent d68376f2ac
commit a457542fb1
5 changed files with 138 additions and 3 deletions

View file

@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef LABWC_PARSE_DOUBLE_H
#define LABWC_PARSE_DOUBLE_H
#include <assert.h>
#include <stdbool.h>
/**
* set_double() - Parse double-precision value of string.
* @str: String to parse
* @val: Storage for parsed value
*
* Return: true if string was parsed, false if not
*
* NOTE: If this function returns false, the value at *val will be untouched.
*/
bool set_double(const char *str, double *val);
static inline bool
set_float(const char *str, float *val)
{
assert(val);
double d;
if (set_double(str, &d)) {
*val = d;
return true;
}
return false;
}
#endif /* LABWC_PARSE_DOUBLE_H */

View file

@ -10,6 +10,7 @@ labwc_sources += files(
'mem.c', 'mem.c',
'nodename.c', 'nodename.c',
'parse-bool.c', 'parse-bool.c',
'parse-double.c',
'scaled_font_buffer.c', 'scaled_font_buffer.c',
'scaled_scene_buffer.c', 'scaled_scene_buffer.c',
'scene-helpers.c', 'scene-helpers.c',

99
src/common/parse-double.c Normal file
View file

@ -0,0 +1,99 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <wlr/util/log.h>
#include "common/mem.h"
#include "common/parse-double.h"
struct dec_separator {
int index;
bool multiple;
};
struct converted_double {
double value;
bool valid;
};
static struct dec_separator
find_dec_separator(const char *str)
{
struct dec_separator loc = {
.index = -1,
.multiple = false
};
for (int i = 0; *str; i++, str++) {
switch (*str) {
case ',':
case '.':
if (loc.index >= 0) {
loc.multiple = true;
return loc;
} else {
loc.index = i;
}
break;
}
}
return loc;
}
static struct converted_double
convert_double(const char *str)
{
struct converted_double result = {
.value = 0,
.valid = true,
};
char *eptr = NULL;
errno = 0;
result.value = strtod(str, &eptr);
if (errno) {
wlr_log(WLR_ERROR, "value '%s' is out of range", str);
result.valid = false;
}
if (*eptr) {
wlr_log(WLR_ERROR, "value '%s' contains trailing garbage", str);
result.valid = false;
}
return result;
}
bool
set_double(const char *str, double *val)
{
assert(str);
assert(val);
struct dec_separator dloc = find_dec_separator(str);
if (dloc.multiple) {
wlr_log(WLR_ERROR,
"value '%s' contains multiple decimal markers", str);
return false;
}
char *lstr = NULL;
if (dloc.index >= 0) {
lstr = xstrdup(str);
struct lconv *lc = localeconv();
lstr[dloc.index] = *lc->decimal_point;
str = lstr;
}
struct converted_double conv = convert_double(str);
if (conv.valid) {
*val = conv.value;
}
free(lstr);
return conv.valid;
}

View file

@ -21,6 +21,7 @@
#include "common/mem.h" #include "common/mem.h"
#include "common/nodename.h" #include "common/nodename.h"
#include "common/parse-bool.h" #include "common/parse-bool.h"
#include "common/parse-double.h"
#include "common/string-helpers.h" #include "common/string-helpers.h"
#include "config/default-bindings.h" #include "config/default-bindings.h"
#include "config/keybind.h" #include "config/keybind.h"
@ -537,7 +538,7 @@ fill_libinput_category(char *nodename, char *content)
} else if (!strcasecmp(nodename, "leftHanded")) { } else if (!strcasecmp(nodename, "leftHanded")) {
set_bool_as_int(content, &current_libinput_category->left_handed); set_bool_as_int(content, &current_libinput_category->left_handed);
} else if (!strcasecmp(nodename, "pointerSpeed")) { } else if (!strcasecmp(nodename, "pointerSpeed")) {
current_libinput_category->pointer_speed = atof(content); set_float(content, &current_libinput_category->pointer_speed);
if (current_libinput_category->pointer_speed < -1) { if (current_libinput_category->pointer_speed < -1) {
current_libinput_category->pointer_speed = -1; current_libinput_category->pointer_speed = -1;
} else if (current_libinput_category->pointer_speed > 1) { } else if (current_libinput_category->pointer_speed > 1) {
@ -883,7 +884,7 @@ entry(xmlNode *node, char *nodename, char *content)
wlr_log(WLR_ERROR, "invalid doubleClickTime"); wlr_log(WLR_ERROR, "invalid doubleClickTime");
} }
} else if (!strcasecmp(nodename, "scrollFactor.mouse")) { } else if (!strcasecmp(nodename, "scrollFactor.mouse")) {
rc.scroll_factor = atof(content); set_double(content, &rc.scroll_factor);
} else if (!strcasecmp(nodename, "name.context.mouse")) { } else if (!strcasecmp(nodename, "name.context.mouse")) {
current_mouse_context = content; current_mouse_context = content;
current_mousebind = NULL; current_mousebind = NULL;

View file

@ -4,6 +4,7 @@
#include <stdint.h> #include <stdint.h>
#include <strings.h> #include <strings.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "common/parse-double.h"
#include "config/tablet.h" #include "config/tablet.h"
#include "config/rcxml.h" #include "config/rcxml.h"
#include "input/tablet_pad.h" #include "input/tablet_pad.h"
@ -11,7 +12,8 @@
double double
tablet_get_dbl_if_positive(const char *content, const char *name) tablet_get_dbl_if_positive(const char *content, const char *name)
{ {
double value = atof(content); double value = 0;
set_double(content, &value);
if (value < 0) { if (value < 0) {
wlr_log(WLR_ERROR, "Invalid value for tablet area %s", name); wlr_log(WLR_ERROR, "Invalid value for tablet area %s", name);
return 0; return 0;