diff --git a/ggml/src/gguf.cpp b/ggml/src/gguf.cpp index 5c26f751fd..8e8c2f0e68 100644 --- a/ggml/src/gguf.cpp +++ b/ggml/src/gguf.cpp @@ -792,7 +792,16 @@ static struct gguf_context * gguf_init_from_reader(const struct gguf_reader & gr gguf_free(ctx); return nullptr; } - size_t padded_size = GGML_PAD(ggml_nbytes(&ti.t), ctx->alignment); + const size_t nbytes = ggml_nbytes(&ti.t); + // GGML_PAD adds (alignment - 1) to nbytes. when nbytes is near + // SIZE_MAX this wraps to 0 and makes the check below dead. + if (nbytes > SIZE_MAX - (ctx->alignment - 1)) { + GGML_LOG_ERROR("%s: tensor '%s' size %zu overflows after padding (alignment %zu)\n", + __func__, ti.t.name, nbytes, ctx->alignment); + gguf_free(ctx); + return nullptr; + } + const size_t padded_size = GGML_PAD(nbytes, ctx->alignment); if (SIZE_MAX - ctx->size < padded_size) { GGML_LOG_ERROR("%s: tensor '%s' size overflow, cannot accumulate size %zu + %zu\n", __func__, ti.t.name, ctx->size, padded_size); diff --git a/tests/test-gguf.cpp b/tests/test-gguf.cpp index f40d6984bf..6c63ecaeb4 100644 --- a/tests/test-gguf.cpp +++ b/tests/test-gguf.cpp @@ -40,6 +40,7 @@ enum handcrafted_file_type { HANDCRAFTED_TENSORS_ZERO_DIM = 35 + offset_has_tensors, HANDCRAFTED_TENSORS_NE_TOO_BIG = 40 + offset_has_tensors, HANDCRAFTED_TENSORS_NBYTES_TOO_BIG = 45 + offset_has_tensors, + HANDCRAFTED_TENSORS_NBYTES_PAD_WRAP = 46 + offset_has_tensors, HANDCRAFTED_TENSORS_BAD_TYPE = 50 + offset_has_tensors, HANDCRAFTED_TENSORS_BAD_OFFSET = 60 + offset_has_tensors, HANDCRAFTED_TENSORS_DUPLICATE_NAME = 70 + offset_has_tensors, @@ -80,6 +81,7 @@ static std::string handcrafted_file_type_name(const enum handcrafted_file_type h case HANDCRAFTED_TENSORS_ZERO_DIM: return "TENSORS_ZERO_DIM"; case HANDCRAFTED_TENSORS_NE_TOO_BIG: return "TENSORS_NE_TOO_BIG"; case HANDCRAFTED_TENSORS_NBYTES_TOO_BIG: return "TENSORS_NBYTES_TOO_BIG"; + case HANDCRAFTED_TENSORS_NBYTES_PAD_WRAP: return "TENSORS_NBYTES_PAD_WRAP"; case HANDCRAFTED_TENSORS_BAD_TYPE: return "TENSORS_BAD_TYPE"; case HANDCRAFTED_TENSORS_BAD_OFFSET: return "TENSORS_BAD_OFFSET"; case HANDCRAFTED_TENSORS_DUPLICATE_NAME: return "TENSORS_DUPLICATE_NAME"; @@ -250,6 +252,13 @@ static FILE * get_handcrafted_file(const unsigned int seed, const enum handcraft tensor_configs[1] = { GGML_TYPE_I8, { 0x7FFFFFFFFFFFFFC0, 1, 1, 1 } }; } + if (hft == HANDCRAFTED_TENSORS_NBYTES_PAD_WRAP) { + tensor_configs.resize(1); + // F32 with ne = [4, 2^30-1, 2^30+1, 1] so ggml_nbytes = 2^64 - 16. + // this hits the GGML_PAD wrap window: pad wraps to 0. + tensor_configs[0] = { GGML_TYPE_F32, { 4, INT64_C(1073741823), INT64_C(1073741825), 1 } }; + } + if (hft == HANDCRAFTED_HEADER_BAD_N_TENSORS) { const uint64_t n_tensors = -1; helper_write(file, n_tensors); @@ -774,6 +783,7 @@ static std::pair test_handcrafted_file(const unsigned int seed) { HANDCRAFTED_TENSORS_ZERO_DIM, HANDCRAFTED_TENSORS_NE_TOO_BIG, HANDCRAFTED_TENSORS_NBYTES_TOO_BIG, + HANDCRAFTED_TENSORS_NBYTES_PAD_WRAP, HANDCRAFTED_TENSORS_BAD_TYPE, HANDCRAFTED_TENSORS_BAD_OFFSET, HANDCRAFTED_TENSORS_DUPLICATE_NAME,