Coverage Report

Created: 2025-11-24 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/llama.cpp/fuzzers/fuzz_structured.cpp
Line
Count
Source
1
/* Copyright 2024 Google LLC
2
Licensed under the Apache License, Version 2.0 (the "License");
3
you may not use this file except in compliance with the License.
4
You may obtain a copy of the License at
5
      http://www.apache.org/licenses/LICENSE-2.0
6
Unless required by applicable law or agreed to in writing, software
7
distributed under the License is distributed on an "AS IS" BASIS,
8
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
See the License for the specific language governing permissions and
10
limitations under the License.
11
*/
12
13
#include "llama.h"
14
#include <iostream>
15
#include <string>
16
#include <vector>
17
18
#include <setjmp.h>
19
#include <unistd.h>
20
21
#include <fuzzer/FuzzedDataProvider.h>
22
#include <string.h>
23
24
jmp_buf fuzzing_jmp_buf;
25
26
50
#define NUM_OVERRIDES 75
27
struct llama_model_kv_override fuzz_kv_overrides[NUM_OVERRIDES + 1];
28
29
llama_model_kv_override_type arrayed_enums[4] = {
30
    LLAMA_KV_OVERRIDE_TYPE_INT, LLAMA_KV_OVERRIDE_TYPE_FLOAT,
31
    LLAMA_KV_OVERRIDE_TYPE_BOOL, LLAMA_KV_OVERRIDE_TYPE_STR};
32
33
std::vector<std::string> possible_keys = {
34
    "general.type",
35
    "general.quantization_version",
36
    "general.alignment",
37
    "general.name",
38
    "general.author",
39
    "general.version",
40
    "general.url",
41
    "general.description",
42
    "general.license",
43
    "general.source.url",
44
    "general.source.huggingface.repository",
45
    "split.no",
46
    "split.count",
47
    "split.tensors.count",
48
    "tokenizer.ggml.model",
49
    "tokenizer.ggml.pre",
50
    "tokenizer.ggml.tokens",
51
    "tokenizer.ggml.token_type",
52
    "tokenizer.ggml.token_type_count",
53
    "tokenizer.ggml.scores",
54
    "tokenizer.ggml.merges",
55
    "tokenizer.ggml.bos_token_id",
56
    "tokenizer.ggml.eos_token_id",
57
    "tokenizer.ggml.unknown_token_id",
58
    "tokenizer.ggml.seperator_token_id",
59
    "tokenizer.ggml.padding_token_id",
60
    "tokenizer.ggml.cls_token_id",
61
    "tokenizer.ggml.mask_token_id",
62
    "tokenizer.ggml.add_bos_token",
63
    "tokenizer.ggml.add_eos_token",
64
    "tokenizer.ggml.add_space_prefix",
65
    "tokenizer.ggml.remove_extra_whitespaces",
66
    "tokenizer.ggml.precompiled_charsmap",
67
    "tokenizer.huggingface.json",
68
    "tokenizer.rwkv.world",
69
    "tokenizer.ggml.prefix_token_id",
70
    "tokenizer.ggml.suffix_token_id",
71
    "tokenizer.ggml.middle_token_id",
72
    "tokenizer.ggml.eot_token_id",
73
    "tokenizer.ggml.eom_token_id",
74
    "adapter.type",
75
    "adapter.lora.alpha",
76
77
};
78
79
std::vector<std::string> possible_architectures = {
80
    "llama",        "falcon",   "grok",      "gpt2",   "gptj",  "gptneox",
81
    "mpt",          "baichuan", "starcoder", "refact", "bert",  "nomic-bert",
82
    "jina-bert-v2", "bloom",    "stablelm",  "qwen",   "qwen2",
83
};
84
85
std::vector<std::string> possible_prefix_keys = {
86
    ".vocab_size",
87
    ".context_length",
88
    ".embedding_length",
89
    ".block_count",
90
    ".leading_dense_block_count",
91
    ".feed_forward_length",
92
    ".expert_feed_forward_length",
93
    ".expert_shared_feed_forward_length",
94
    ".use_parallel_residual",
95
    ".tensor_data_layout",
96
    ".expert_count",
97
    ".expert_used_count",
98
    ".expert_shared_count",
99
    ".expert_weights_scale",
100
    ".pooling_type",
101
    ".logit_scale",
102
    ".decoder_start_token_id",
103
    ".attn_logit_softcapping",
104
    ".final_logit_softcapping",
105
    ".rescale_every_n_layers",
106
    ".time_mix_extra_dim",
107
    ".time_decay_extra_dim",
108
    ".attention.head_count",
109
    ".attention.head_count_kv",
110
    ".attention.max_alibi_bias",
111
    ".attention.clamp_kqv",
112
    ".attention.key_length",
113
    ".attention.value_length",
114
    ".attention.layer_norm_epsilon",
115
    ".attention.layer_norm_rms_epsilon",
116
    ".attention.causal",
117
    ".attention.q_lora_rank",
118
    ".attention.kv_lora_rank",
119
    ".attention.relative_buckets_count",
120
    ".attention.sliding_window",
121
    ".rope.dimension_count",
122
    ".rope.freq_base",
123
    ".rope.scale_linear",
124
    ".rope.scaling.type",
125
    ".rope.scaling.factor",
126
    ".rope.scaling.attn_factor",
127
    ".rope.scaling.original_context_length",
128
    ".rope.scaling.finetuned",
129
    ".rope.scaling.yarn_log_multiplier",
130
    ".ssm.conv_kernel",
131
    ".ssm.inner_size",
132
    ".ssm.state_size",
133
    ".ssm.time_step_rank",
134
    ".ssm.dt_b_c_rms",
135
    ".wkv.head_size",
136
};
137
138
0
extern "C" void __wrap_abort(void) { longjmp(fuzzing_jmp_buf, 1); }
139
140
70
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
141
70
  if (size < 256) {
142
14
    return 0;
143
14
  }
144
56
  llama_backend_init();
145
56
  FuzzedDataProvider fdp(data, size);
146
147
56
  auto params = llama_model_params{};
148
56
  memset(&params, 0x0, sizeof(struct llama_model_params));
149
56
  params.use_mmap = false;
150
56
  params.progress_callback = [](float progress, void *ctx) {
151
0
    (void)ctx;
152
0
    return progress > 0.50;
153
0
  };
154
155
56
  int overwrite_idx = 0;
156
157
  // set the architecture
158
56
  std::string arch_key = "general.architecture";
159
56
  uint8_t arch_index =
160
56
      fdp.ConsumeIntegralInRange<uint8_t>(0, possible_architectures.size() - 1);
161
162
56
  std::string arch_val = std::string(possible_architectures[arch_index]);
163
56
  fuzz_kv_overrides[overwrite_idx].tag = LLAMA_KV_OVERRIDE_TYPE_STR;
164
56
  strcpy(fuzz_kv_overrides[overwrite_idx].key, arch_key.c_str());
165
56
  strcpy(fuzz_kv_overrides[overwrite_idx].val_str, arch_val.c_str());
166
56
  overwrite_idx++;
167
168
2.85k
  for (int i = 0; i < possible_prefix_keys.size(); i++) {
169
2.80k
    std::string key;
170
2.80k
    std::string val;
171
172
    // Get the key
173
2.80k
    key = arch_val + possible_prefix_keys[i];
174
2.80k
    val = fdp.ConsumeRandomLengthString(32);
175
176
    // Copy the data into the overrides array
177
2.80k
    fuzz_kv_overrides[overwrite_idx].tag = fdp.PickValueInArray(arrayed_enums);
178
2.80k
    strcpy(fuzz_kv_overrides[overwrite_idx].key, key.c_str());
179
2.80k
    strcpy(fuzz_kv_overrides[overwrite_idx].val_str, val.c_str());
180
2.80k
    overwrite_idx++;
181
2.80k
  }
182
183
  // Create the model
184
56
  std::string model_payload = fdp.ConsumeRandomLengthString();
185
56
  if (model_payload.size() < 10) {
186
54
    return 0;
187
54
  }
188
2
  model_payload[0] = 'G';
189
2
  model_payload[1] = 'G';
190
2
  model_payload[2] = 'U';
191
2
  model_payload[3] = 'F';
192
193
2
  char filename[256];
194
2
  sprintf(filename, "/tmp/libfuzzer.%d", getpid());
195
196
2
  FILE *fp = fopen(filename, "wb");
197
2
  if (!fp) {
198
0
    return 0;
199
0
  }
200
2
  fwrite(model_payload.data(), model_payload.size(), 1, fp);
201
2
  fclose(fp);
202
203
  // Override an arbitrary set of arguments
204
50
  for (int i = overwrite_idx; i < NUM_OVERRIDES; i++) {
205
48
    std::string key;
206
48
    std::string val;
207
208
    // Get the key
209
48
    if (fdp.ConsumeProbability<float>() > 0.90) {
210
0
      key = fdp.ConsumeRandomLengthString(20);
211
48
    } else {
212
48
      int i = fdp.ConsumeIntegralInRange<int>(0, possible_keys.size() - 1);
213
48
      key = possible_keys[i];
214
48
    }
215
48
    val = fdp.ConsumeRandomLengthString(30);
216
217
    // Copy the data into the overrides array
218
48
    fuzz_kv_overrides[i].tag = fdp.PickValueInArray(arrayed_enums);
219
48
    strcpy(fuzz_kv_overrides[i].key, key.c_str());
220
48
    strcpy(fuzz_kv_overrides[i].val_str, val.c_str());
221
48
  }
222
223
  // For debugging
224
  // std::cout << "--- overwrote ---\n";
225
  // for (int m = 0; m < NUM_OVERRIDES-1; m++) {
226
  //  std::cout << "===  " << fuzz_kv_overrides[m].key << "\n";
227
  //}
228
  // std::cout << "#############\n";
229
230
2
  params.kv_overrides =
231
2
      (const struct llama_model_kv_override *)fuzz_kv_overrides;
232
233
2
  if (setjmp(fuzzing_jmp_buf) == 0) {
234
2
    auto *model = llama_load_model_from_file(filename, params);
235
2
    if (model != nullptr) {
236
0
      llama_free_model(model);
237
0
    }
238
2
  }
239
2
  llama_backend_free();
240
241
  // close any open descriptors.
242
2.04k
  for (int i = 3; i < 1024; i++) {
243
2.04k
    close(i);
244
2.04k
  }
245
246
2
  unlink(filename);
247
2
  return 0;
248
2
}