Skip to content

Commit 1d9ed2e

Browse files
committed
file/config_file: reject non-numeric input in integer getters
config_get_int(), config_get_uint(), config_get_uint64() and config_get_hex() all used this pattern: errno = 0; val = strtol(entry->value, NULL, 0); if (errno == 0) { *in = val; return true; } strtol returns 0 (without setting errno) when handed a string that has no leading digits at all -- so a config line like width = abc silently produced width = 0 and the getter reported success. The user sees the setting "accepted" with a bogus value and no way to tell anything went wrong. config_get_size_t() in the same file already used the correct pattern; this patch applies it to the other four. Each fixed getter now: - captures the end pointer from strtol/strtoul/strtoull - rejects if errno was set (overflow) - rejects if zero digits were consumed (end == entry->value) - rejects if trailing garbage remains (*end != '\0') - for config_get_int / config_get_uint / config_get_hex, also rejects values outside the destination type's range (strtol on 64-bit systems returns a 64-bit long that must fit in int) Behavioural change: values that previously silently became zero now return false and leave *in untouched. This matches the documented "@return true if found, otherwise false" contract in config_file.h -- the prior behaviour violated it by returning true for not-a-number strings. Callers that relied on the bogus zero were already silently broken; they now get explicit failure and can fall back to a default.
1 parent e044ef6 commit 1d9ed2e

4 files changed

Lines changed: 585 additions & 28 deletions

File tree

libretro-common/file/config_file.c

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <stdio.h>
2626
#include <ctype.h>
2727
#include <errno.h>
28+
#include <limits.h>
2829

2930
#include <retro_miscellaneous.h>
3031
#include <compat/strl.h>
@@ -963,17 +964,22 @@ bool config_get_float(config_file_t *conf, const char *key, float *in)
963964
bool config_get_int(config_file_t *conf, const char *key, int *in)
964965
{
965966
const struct config_entry_list *entry = config_get_entry(conf, key);
966-
errno = 0;
967967

968968
if (entry)
969969
{
970-
int val = (int)strtol(entry->value, NULL, 0);
970+
long val;
971+
char *end = NULL;
972+
errno = 0;
973+
val = strtol(entry->value, &end, 0);
971974

972-
if (errno == 0)
973-
{
974-
*in = val;
975-
return true;
976-
}
975+
if (errno != 0 || end == entry->value || *end != '\0')
976+
return false;
977+
978+
if (val < INT_MIN || val > INT_MAX)
979+
return false;
980+
981+
*in = (int)val;
982+
return true;
977983
}
978984

979985
return false;
@@ -1009,17 +1015,19 @@ bool config_get_size_t(config_file_t *conf, const char *key, size_t *in)
10091015
bool config_get_uint64(config_file_t *conf, const char *key, uint64_t *in)
10101016
{
10111017
const struct config_entry_list *entry = config_get_entry(conf, key);
1012-
errno = 0;
10131018

10141019
if (entry)
10151020
{
1016-
uint64_t val = (uint64_t)strtoull(entry->value, NULL, 0);
1021+
uint64_t val;
1022+
char *end = NULL;
1023+
errno = 0;
1024+
val = (uint64_t)strtoull(entry->value, &end, 0);
10171025

1018-
if (errno == 0)
1019-
{
1020-
*in = val;
1021-
return true;
1022-
}
1026+
if (errno != 0 || end == entry->value || *end != '\0')
1027+
return false;
1028+
1029+
*in = val;
1030+
return true;
10231031
}
10241032
return false;
10251033
}
@@ -1028,17 +1036,22 @@ bool config_get_uint64(config_file_t *conf, const char *key, uint64_t *in)
10281036
bool config_get_uint(config_file_t *conf, const char *key, unsigned *in)
10291037
{
10301038
const struct config_entry_list *entry = config_get_entry(conf, key);
1031-
errno = 0;
10321039

10331040
if (entry)
10341041
{
1035-
unsigned val = (unsigned)strtoul(entry->value, NULL, 0);
1042+
unsigned long val;
1043+
char *end = NULL;
1044+
errno = 0;
1045+
val = strtoul(entry->value, &end, 0);
10361046

1037-
if (errno == 0)
1038-
{
1039-
*in = val;
1040-
return true;
1041-
}
1047+
if (errno != 0 || end == entry->value || *end != '\0')
1048+
return false;
1049+
1050+
if (val > UINT_MAX)
1051+
return false;
1052+
1053+
*in = (unsigned)val;
1054+
return true;
10421055
}
10431056

10441057
return false;
@@ -1047,17 +1060,22 @@ bool config_get_uint(config_file_t *conf, const char *key, unsigned *in)
10471060
bool config_get_hex(config_file_t *conf, const char *key, unsigned *in)
10481061
{
10491062
const struct config_entry_list *entry = config_get_entry(conf, key);
1050-
errno = 0;
10511063

10521064
if (entry)
10531065
{
1054-
unsigned val = (unsigned)strtoul(entry->value, NULL, 16);
1066+
unsigned long val;
1067+
char *end = NULL;
1068+
errno = 0;
1069+
val = strtoul(entry->value, &end, 16);
10551070

1056-
if (errno == 0)
1057-
{
1058-
*in = val;
1059-
return true;
1060-
}
1071+
if (errno != 0 || end == entry->value || *end != '\0')
1072+
return false;
1073+
1074+
if (val > UINT_MAX)
1075+
return false;
1076+
1077+
*in = (unsigned)val;
1078+
return true;
10611079
}
10621080

10631081
return false;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
TARGET := archive_zip_test
2+
3+
LIBRETRO_COMM_DIR := ../../..
4+
5+
SOURCES := \
6+
archive_zip_test.c \
7+
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
8+
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
9+
$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
10+
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
11+
$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
12+
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
13+
$(LIBRETRO_COMM_DIR)/file/archive_file.c \
14+
$(LIBRETRO_COMM_DIR)/file/archive_file_zlib.c \
15+
$(LIBRETRO_COMM_DIR)/file/file_path.c \
16+
$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
17+
$(LIBRETRO_COMM_DIR)/lists/string_list.c \
18+
$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
19+
$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \
20+
$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \
21+
$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \
22+
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
23+
$(LIBRETRO_COMM_DIR)/time/rtime.c
24+
25+
OBJS := $(SOURCES:.c=.o)
26+
27+
CFLAGS += -Wall -pedantic -std=gnu99 -g -DHAVE_ZLIB -I$(LIBRETRO_COMM_DIR)/include
28+
LDFLAGS += -lz
29+
30+
all: $(TARGET)
31+
32+
%.o: %.c
33+
$(CC) -c -o $@ $< $(CFLAGS)
34+
35+
$(TARGET): $(OBJS)
36+
$(CC) -o $@ $^ $(LDFLAGS)
37+
38+
clean:
39+
rm -f $(TARGET) $(OBJS)
40+
41+
.PHONY: clean

0 commit comments

Comments
 (0)