Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions fuzz/fuzz_decode_buf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#define MINIMP3_IMPLEMENTATION
#define MINIMP3_ALLOW_MONO_STEREO_TRANSITION
#include "minimp3_ex.h"

static int iterate_cb(void *user_data, const uint8_t *frame, int frame_size,
int free_format_bytes, size_t buf_size, uint64_t offset,
mp3dec_frame_info_t *info) {
(void)user_data;
(void)frame;
(void)frame_size;
(void)free_format_bytes;
(void)buf_size;
(void)offset;
(void)info;
return 0;
}

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 4)
return 0;
if (size > 128 * 1024)
size = 128 * 1024;

/* Use first byte to select API path */
uint8_t selector = data[0] & 0x01;
const uint8_t *buf = data + 1;
size_t buf_size = size - 1;

if (selector == 0) {
/* Test mp3dec_load_buf: full buffer decode */
mp3dec_t dec;
mp3dec_file_info_t info;
memset(&info, 0, sizeof(info));

mp3dec_load_buf(&dec, buf, buf_size, &info, NULL, NULL);

if (info.buffer)
free(info.buffer);
} else {
/* Test mp3dec_iterate_buf: frame iteration */
mp3dec_iterate_buf(buf, buf_size, iterate_cb, NULL);
}

return 0;
}
65 changes: 65 additions & 0 deletions fuzz/fuzz_decode_ex.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#define MINIMP3_IMPLEMENTATION
#define MINIMP3_ALLOW_MONO_STEREO_TRANSITION
#include "minimp3_ex.h"

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 8)
return 0;
if (size > 128 * 1024)
size = 128 * 1024;

/* Consume first 4 bytes for seek position and flags */
uint32_t seek_pos = ((uint32_t)data[0] << 24) | ((uint32_t)data[1] << 16) |
((uint32_t)data[2] << 8) | (uint32_t)data[3];
int flags = (data[4] & 0x01) ? MP3D_SEEK_TO_BYTE : MP3D_SEEK_TO_SAMPLE;
flags |= MP3D_ALLOW_MONO_STEREO_TRANSITION;

const uint8_t *buf = data + 5;
size_t buf_size = size - 5;

mp3dec_ex_t dec;
if (mp3dec_ex_open_buf(&dec, buf, buf_size, flags) == 0) {
/* Read some samples */
mp3d_sample_t pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
size_t read_total = 0;
size_t readed;

do {
readed = mp3dec_ex_read(&dec, pcm, MINIMP3_MAX_SAMPLES_PER_FRAME);
read_total += readed;
/* Safety: limit total reads to prevent excessive runtime */
if (read_total > 1024 * 1024)
break;
} while (readed > 0);

/* Test seek */
mp3dec_ex_seek(&dec, (uint64_t)seek_pos);

/* Read after seek */
readed = mp3dec_ex_read(&dec, pcm, MINIMP3_MAX_SAMPLES_PER_FRAME);
(void)readed;

mp3dec_ex_close(&dec);
}

return 0;
}
55 changes: 55 additions & 0 deletions fuzz/fuzz_decode_frame.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdint.h>
#include <stddef.h>
#include <string.h>

#define MINIMP3_IMPLEMENTATION
#include "minimp3.h"

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 4)
return 0;
/* Cap input to avoid OOM on very large inputs */
if (size > 128 * 1024)
size = 128 * 1024;

mp3dec_t dec;
mp3dec_init(&dec);

const uint8_t *buf = data;
size_t remaining = size;

/* Decode frames until the buffer is exhausted */
while (remaining > 0) {
mp3dec_frame_info_t info;
mp3d_sample_t pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];

int samples = mp3dec_decode_frame(&dec, buf, (int)remaining, pcm, &info);

if (info.frame_bytes > 0) {
if ((size_t)info.frame_bytes > remaining)
break;
buf += info.frame_bytes;
remaining -= info.frame_bytes;
} else {
/* No frame found, skip one byte */
buf++;
remaining--;
}
}

return 0;
}
38 changes: 38 additions & 0 deletions fuzz/mp3.dict
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# MP3 frame sync words (0xFFE0 mask)
# MPEG1 Layer3
kw_sync_mp1l3="\xff\xfb"
kw_sync_mp1l3_2="\xff\xfa"
# MPEG1 Layer2
kw_sync_mp1l2="\xff\xfd"
kw_sync_mp1l2_2="\xff\xfc"
# MPEG1 Layer1
kw_sync_mp1l1="\xff\xfe"
# MPEG2 Layer3
kw_sync_mp2l3="\xff\xf3"
kw_sync_mp2l3_2="\xff\xf2"
# MPEG2.5 Layer3
kw_sync_mp25l3="\xff\xe3"
kw_sync_mp25l3_2="\xff\xe2"

# ID3v2 header
kw_id3v2="ID3"
# ID3v1 header
kw_id3v1="TAG"
# APE tag
kw_ape="APETAGEX"

# Xing VBR header
kw_xing="Xing"
kw_info="Info"
# VBRI header
kw_vbri="VBRI"

# Common frame header bytes
kw_hdr1="\xff\xfb\x90\x00"
kw_hdr2="\xff\xfb\x90\x64"
kw_hdr3="\xff\xfb\x92\x00"
kw_hdr4="\xff\xf3\x90\x00"
kw_hdr5="\xff\xe3\x90\x00"

# Common bitrates (128kbps stereo 44100Hz)
kw_common="\xff\xfb\x90\x04"