Add fuzz target for FileRef parsing under tests/fuzzing (#1433)

Adds a libFuzzer target parsing arbitrary input through TagLib::FileRef,
a format magic dictionary, and a README with build and run instructions.
Fully decoupled from the normal build as discussed in #1431.
This commit is contained in:
roshan
2026-08-30 13:07:57 +02:00
committed by GitHub
parent 5fa6fa6c2f
commit d6c5a8d888
3 changed files with 208 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
# Fuzzing taglib
This directory contains a libFuzzer target for taglib's generic parsing entry
point. It is intentionally decoupled from the normal CMake build: nothing in
the main source tree references it, and it is compiled on demand with the
commands below.
## Target
`taglib_fileref_fuzzer.cpp` parses arbitrary in-memory input through
`TagLib::FileRef` with a `ByteVectorStream`, exercising file type detection
plus tag, audio property and complex property (picture) parsing for all
supported formats: MP3/ID3v1/ID3v2, FLAC, Ogg Vorbis/Opus/Speex, MP4/M4A,
WAV/AIFF, APE/MPC/WavPack, DSF, DSDIFF, Matroska/WebM, Shorten, TrueAudio
and the tracker module formats.
`taglib.dict` is a libFuzzer dictionary of format magic numbers for the
supported file types.
## Building and running
Build taglib first, for example:
```
cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF
cmake --build build -j$(nproc)
```
Then compile the fuzz target against it with the libFuzzer and
AddressSanitizer flags:
```
clang++ -std=c++17 -g -fsanitize=fuzzer,address -fno-omit-frame-pointer \
-I taglib -I taglib/toolkit -I build \
tests/fuzzing/taglib_fileref_fuzzer.cpp \
build/taglib/libtag.a -lz \
-o taglib_fileref_fuzzer
```
Run it over taglib's own test data as a seed corpus (plus a dictionary):
```
./taglib_fileref_fuzzer -dict=tests/fuzzing/taglib.dict tests/data/
```
## OSS-Fuzz
This target is also built continuously by Google's OSS-Fuzz service for the
taglib project, which runs it under AddressSanitizer and
UndefinedBehaviorSanitizer with the test data as seed corpus.
+96
View File
@@ -0,0 +1,96 @@
# Copyright 2026 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.
# Magic numbers and markers for the file formats taglib parses.
# ID3v2 / ID3v1
"ID3"
"TAG"
"APETAGEX"
# MPEG audio frame sync
"\xFF\xFB"
"\xFF\xFA"
"\xFF\xF3"
"\xFF\xF2"
# Ogg (Vorbis, Opus, Speex, FLAC-in-Ogg)
"OggS"
"\x01vorbis"
"OpusTags"
"\x80Speex"
# FLAC
"fLaC"
# MP4 / M4A / iTunes
"ftyp"
"M4A "
"mp42"
"isom"
"moov"
"udta"
"meta"
"ilst"
"covr"
"free"
# RIFF / WAV
"RIFF"
"WAVE"
"fmt "
"data"
"LIST"
"ID3 "
# AIFF
"FORM"
"AIFF"
"AIFC"
"COMM"
"SSND"
# APE / MPC / WavPack
"MAC "
"MP+"
"wvpk"
# DSF / DSDIFF
"DSD "
"FRM8"
"DSd "
"DSD"
# Matroska / WebM (EBML)
"\x1A\x45\xDF\xA3"
"matroska"
"webm"
"Segment"
"Tags"
# Tracker modules (IT, XM, S3M, MOD)
"IMPM"
"Extended Module"
"SCRM"
"M.K."
"M!K!"
"FLT4"
"4CHN"
"6CHN"
# TrueAudio
"TTA1"
# Shorten (ajkg magic)
"ajkg"
+62
View File
@@ -0,0 +1,62 @@
// Copyright 2026 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.
// Fuzzes TagLib's generic file type detection and tag/audio-property parsing
// over all supported formats (MP3/ID3v2, FLAC, OGG/Vorbis/Opus/Speex, MP4/AAC,
// WAV, AIFF, APE, MPC, WavPack, DSF, DSDIFF, tracker formats, ...).
#include <cstddef>
#include <cstdint>
#include <audioproperties.h>
#include <fileref.h>
#include <tag.h>
#include <tbytevector.h>
#include <tbytevectorstream.h>
#include <tpropertymap.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
const TagLib::ByteVector input(reinterpret_cast<const char *>(data),
static_cast<unsigned int>(size));
TagLib::ByteVectorStream stream(input);
{
TagLib::FileRef ref(&stream, /*readAudioProperties=*/true,
TagLib::AudioProperties::Average);
if (!ref.isNull()) {
if (ref.tag()) {
const TagLib::Tag *tag = ref.tag();
// Touch the standard fields to force a full tag parse.
(void)tag->title();
(void)tag->artist();
(void)tag->album();
(void)tag->comment();
(void)tag->genre();
(void)tag->year();
(void)tag->track();
(void)tag->properties();
}
// Parse embedded pictures and other complex properties.
(void)ref.complexProperties("PICTURE");
if (ref.audioProperties()) {
const TagLib::AudioProperties *props = ref.audioProperties();
(void)props->lengthInSeconds();
(void)props->lengthInMilliseconds();
(void)props->bitrate();
(void)props->sampleRate();
(void)props->channels();
}
}
} // FileRef is destroyed before the stream it borrows.
return 0;
}