@@ -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