Skip to content

Commit 3842762

Browse files
author
crispasr integration
committed
Merge branch 'fix/mmap-segfault' into main
2 parents 70f09b6 + f77fd43 commit 3842762

1 file changed

Lines changed: 36 additions & 3 deletions

File tree

src/core/gguf_loader.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ bool load_weights(const char* path, ggml_backend_t backend, const char* model_ta
677677
}
678678
const size_t data_off = gguf_get_data_offset(gctx);
679679
std::vector<uint8_t> tbuf;
680+
bool load_ok = true;
680681
for (ggml_tensor* t = ggml_get_first_tensor(out.ctx); t; t = ggml_get_next_tensor(out.ctx, t)) {
681682
out.tensors[ggml_get_name(t)] = t;
682683
const int64_t tid = gguf_find_tensor(gctx, ggml_get_name(t));
@@ -687,17 +688,36 @@ bool load_weights(const char* path, ggml_backend_t backend, const char* model_ta
687688
if (tbuf.size() < nbytes)
688689
tbuf.resize(nbytes);
689690
#if defined(_WIN32)
690-
if (_fseeki64(fp, (int64_t)(data_off + off), SEEK_SET) != 0)
691+
if (_fseeki64(fp, (int64_t)(data_off + off), SEEK_SET) != 0) {
692+
fprintf(stderr, "%s: fseek failed for tensor '%s' — file truncated?\n", tag, ggml_get_name(t));
693+
load_ok = false;
691694
break;
695+
}
692696
#else
693-
if (fseeko(fp, (off_t)(data_off + off), SEEK_SET) != 0)
697+
if (fseeko(fp, (off_t)(data_off + off), SEEK_SET) != 0) {
698+
fprintf(stderr, "%s: fseek failed for tensor '%s' — file truncated?\n", tag, ggml_get_name(t));
699+
load_ok = false;
694700
break;
701+
}
695702
#endif
696-
if (fread(tbuf.data(), 1, nbytes, fp) != nbytes)
703+
if (fread(tbuf.data(), 1, nbytes, fp) != nbytes) {
704+
fprintf(stderr, "%s: short read for tensor '%s' (%zu bytes expected) — file truncated?\n",
705+
tag, ggml_get_name(t), nbytes);
706+
load_ok = false;
697707
break;
708+
}
698709
ggml_backend_tensor_set(t, tbuf.data(), 0, nbytes);
699710
}
700711
fclose(fp);
712+
if (!load_ok) {
713+
fprintf(stderr, "%s: legacy loader failed — model file may be truncated or corrupt\n", tag);
714+
gguf_free(gctx);
715+
ggml_backend_buffer_free(out.buf);
716+
out.buf = nullptr;
717+
ggml_free(out.ctx);
718+
out.ctx = nullptr;
719+
return false;
720+
}
701721
} else {
702722
const size_t data_off = gguf_get_data_offset(gctx);
703723
for (ggml_tensor* t = ggml_get_first_tensor(out.ctx); t; t = ggml_get_next_tensor(out.ctx, t)) {
@@ -707,6 +727,19 @@ bool load_weights(const char* path, ggml_backend_t backend, const char* model_ta
707727
continue;
708728
const size_t off = gguf_get_tensor_offset(gctx, tid);
709729
const size_t nbytes = ggml_nbytes(t);
730+
// Bounds check: prevent segfault on truncated GGUF files
731+
if (data_off + off + nbytes > mf.size) {
732+
fprintf(stderr,
733+
"%s: mmap legacy path: tensor '%s' exceeds file bounds "
734+
"(off=%zu + nbytes=%zu > file_size=%zu) — file truncated?\n",
735+
tag, ggml_get_name(t), data_off + off, nbytes, mf.size);
736+
gguf_free(gctx);
737+
ggml_backend_buffer_free(out.buf);
738+
out.buf = nullptr;
739+
ggml_free(out.ctx);
740+
out.ctx = nullptr;
741+
return false;
742+
}
710743
ggml_backend_tensor_set(t, (const char*)mf.base + data_off + off, 0, nbytes);
711744
}
712745
}

0 commit comments

Comments
 (0)