From b62520af9eb75da57fc874bc08684d7f9ff4a718 Mon Sep 17 00:00:00 2001 From: Larpon Date: Sun, 3 Oct 2021 17:24:06 +0200 Subject: [PATCH] os: fix rare crash in read_file. Fix #12052 (#12053) --- vlib/os/os.c.v | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/vlib/os/os.c.v b/vlib/os/os.c.v index 0d339124db..0c06bec908 100644 --- a/vlib/os/os.c.v +++ b/vlib/os/os.c.v @@ -86,13 +86,19 @@ pub fn read_bytes(path string) ?[]byte { if fsize < 0 { return error('ftell failed') } + len := int(fsize) + // On some systems C.ftell can return values in the 64-bit range + // that, when cast to `int`, can result in values below 0. + if i64(len) < fsize { + return error('$fsize cast to int results in ${int(fsize)})') + } C.rewind(fp) - mut res := []byte{len: int(fsize)} - nr_read_elements := int(C.fread(res.data, fsize, 1, fp)) + mut res := []byte{len: len} + nr_read_elements := int(C.fread(res.data, len, 1, fp)) if nr_read_elements == 0 && fsize > 0 { return error('fread failed') } - res.trim(nr_read_elements * int(fsize)) + res.trim(nr_read_elements * len) return res } @@ -113,9 +119,15 @@ pub fn read_file(path string) ?string { } // C.fseek(fp, 0, SEEK_SET) // same as `C.rewind(fp)` below C.rewind(fp) + allocate := int(fsize) + // On some systems C.ftell can return values in the 64-bit range + // that, when cast to `int`, can result in values below 0. + if i64(allocate) < fsize { + return error('$fsize cast to int results in ${int(fsize)})') + } unsafe { - mut str := malloc_noscan(int(fsize) + 1) - nelements := int(C.fread(str, 1, fsize, fp)) + mut str := malloc_noscan(allocate + 1) + nelements := int(C.fread(str, 1, allocate, fp)) is_eof := int(C.feof(fp)) is_error := int(C.ferror(fp)) if is_eof == 0 && is_error != 0 { @@ -590,7 +602,15 @@ pub fn read_file_array(path string) []T { C.rewind(fp) // read the actual data from the file len := fsize / tsize - buf := unsafe { malloc_noscan(int(fsize)) } + allocate := int(fsize) + // On some systems C.ftell can return values in the 64-bit range + // that, when cast to `int`, can result in values below 0. + if i64(allocate) < fsize { + panic('$fsize cast to int results in ${int(fsize)})') + } + buf := unsafe { + malloc_noscan(allocate) + } nread := C.fread(buf, tsize, len, fp) C.fclose(fp) return unsafe {