salvepilo's picture
Add standalone C++ reproducer
6bf733b verified
Raw
History Blame Contribute Delete
2.87 kB
// Minimal reproducer for Gemma3 integer division-by-zero
// Mirrors the vulnerable code in src/models/gemma3.cpp:32
// and src/llama-model.cpp:1147-1171
//
// Compile: g++ -o reproducer reproducer.cpp -fsanitize=undefined -fno-sanitize-recover=all
// Run: ./reproducer
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <array>
#include <stdexcept>
#include <string>
#define LLAMA_MAX_LAYERS 512
// Mirrors llama_hparams (simplified)
struct llama_hparams {
uint32_t n_embd = 3072; // from gemma3.embedding_length in GGUF
uint32_t n_layer_all = 62; // from gemma3.block_count = 62 β†’ LLM_TYPE_27B
uint32_t n_embd_head_k_full = 0;
std::array<uint32_t, LLAMA_MAX_LAYERS> n_head_arr = {}; // all zeros β€” key missing from GGUF
uint32_t n_head(uint32_t il = 0) const {
return n_head_arr[il]; // returns 0 when key is absent
}
};
enum llm_type { LLM_TYPE_UNKNOWN, LLM_TYPE_1B, LLM_TYPE_4B, LLM_TYPE_8B, LLM_TYPE_12B, LLM_TYPE_27B };
int main() {
llama_hparams hparams;
// --- Mirrors llama-model.cpp:1147 (general hparams loader) ---
// When n_head() == 0, n_embd_head_k_full is set to 0
if (hparams.n_head() > 0) {
hparams.n_embd_head_k_full = hparams.n_embd / hparams.n_head();
} else {
hparams.n_embd_head_k_full = 0;
}
// --- Mirrors gemma3.cpp:20-32 (load_arch_hparams) ---
llm_type type = LLM_TYPE_UNKNOWN;
switch (hparams.n_layer_all) {
case 18: type = LLM_TYPE_UNKNOWN; break; // 270M
case 26: type = LLM_TYPE_1B; break;
case 32: type = LLM_TYPE_8B; break;
case 34: type = LLM_TYPE_4B; break;
case 48: type = LLM_TYPE_12B; break;
case 62: type = LLM_TYPE_27B; break; // <-- block_count=62 triggers this
default: type = LLM_TYPE_UNKNOWN; break;
}
printf("block_count = %u β†’ type = %s\n", hparams.n_layer_all,
type == LLM_TYPE_27B ? "LLM_TYPE_27B" : "other");
printf("n_head(0) = %u (key absent from GGUF β†’ stays 0)\n", hparams.n_head(0));
printf("n_embd = %u\n", hparams.n_embd);
printf("\nExecuting vulnerable line (gemma3.cpp:32):\n");
printf(" hparams.n_embd / hparams.n_head(0) = %u / %u\n",
hparams.n_embd, hparams.n_head(0));
// THE VULNERABLE COMPUTATION β€” mirrors gemma3.cpp:32 exactly
// On x86_64: SIGFPE (exit 136)
// On ARM64: silent UB (SDIV returns 0), UBSan aborts with "division by zero"
float f_attention_scale = (type == LLM_TYPE_27B)
? 1.0f / std::sqrt(float(hparams.n_embd / hparams.n_head(0))) // INTEGER DIV BY ZERO
: 1.0f / std::sqrt(float(hparams.n_embd_head_k_full));
// Should never reach here on x86_64
printf("f_attention_scale = %f (should not reach here on x86_64)\n", f_attention_scale);
return 0;
}