Compare commits

..
2 Commits
Author SHA1 Message Date
Illusion 1142d83adb finally understood why the use-after-free bug happened 2024-09-25 04:13:37 +02:00
Illusion f444efc5af improve the linux example 2024-09-24 23:07:49 +02:00
4 changed files with 32 additions and 33 deletions
+4 -1
View File
@@ -6,6 +6,7 @@ Files:-
Playback issues in the example program that may relate to the decoder:- Playback issues in the example program that may relate to the decoder:-
23 - Crunchy loud noise mixed with the actual audio data 23 - Crunchy loud noise mixed with the actual audio data
uncommon/02 -> 6 channel audio might be incorrect (not a decoder issue afaik)
uncommon/04 -> We get a bits per sample mismatch uncommon/04 -> We get a bits per sample mismatch
uncommon/10 -> We error with Invalid Signature. I assume for these two I should look for the frame sync bits. But maybe my decoder should reject these. idk. uncommon/10 -> We error with Invalid Signature. I assume for these two I should look for the frame sync bits. But maybe my decoder should reject these. idk.
uncommon/11 -> We error with Invalid Signature uncommon/11 -> We error with Invalid Signature
@@ -34,8 +35,10 @@ Things:-
[ ] Speed optimizations [ ] Speed optimizations
[ ] Seeking [ ] Seeking
[ ] Fuzzing to test the stability of the code [ ] Fuzzing to test the stability of the code
[ ] Check if the use-after-free bug happens on Windows, and if so, if the address sanitizer will show us the full stacktrace [x] Check if the use-after-free bug happens on Windows, and if so, if the address sanitizer will show us the full stacktrace
instead of skipping some procs. instead of skipping some procs.
This was caused by `read_data()` and the tee reader writing into the buffer and us using some memory that was freed while the buffer
resized. Solution is to use buffer data BEFORE calling `read_data()`
[ ] Encoder (low priority for now) [ ] Encoder (low priority for now)
+26 -21
View File
@@ -1,4 +1,4 @@
package flac_example package flac_linux_example
import "core:fmt" import "core:fmt"
import "core:mem" import "core:mem"
@@ -51,13 +51,13 @@ main :: proc() {
os.exit(1) os.exit(1)
} }
sample_rate := flac_data.metadata.sample_rate // TODO: channel mapping is incorrect for anything with more than 2 channels.
channels := flac_data.metadata.channels channels := flac_data.metadata.channels
md5_ctx: md5.Context md5_ctx: md5.Context
md5.init(&md5_ctx) md5.init(&md5_ctx)
for { for {
frame, err := flac.read_next_frame(reader, flac_data) frame, err := flac.read_next_frame(reader, flac_data, allocator)
if err != nil { if err != nil {
if err == .EOF { if err == .EOF {
break break
@@ -67,20 +67,24 @@ main :: proc() {
} }
} }
//if frame.sample_rate != sample_rate || frame.channels != channels { if frame.channels != channels {
// sample_rate = frame.sample_rate // Finish playing the previous frame before changing the hw params.
// channels = frame.channels alsa.pcm_drain(handle)
// alsa_err = alsa.pcm_set_params(handle, .S16_LE, .RW_INTERLEAVED, u32(channels), sample_rate, 1, 0)
// if alsa_err < 0 { channels = frame.channels
// fmt.eprintln("Playback open error:", alsa.strerror(alsa_err)) alsa_err = alsa.pcm_set_params(handle, .S16_LE, .RW_INTERLEAVED, u32(channels), flac_data.metadata.sample_rate, 1, 500000)
// os.exit(1) if alsa_err < 0 {
// } fmt.eprintln("Playback open error:", alsa.strerror(alsa_err))
//} os.exit(1)
}
}
// TODO: resampling
// 8 bps audio // 8 bps audio
//converted_samples := make([]u8, len(samples)) //converted_samples := make([]u8, len(frame.samples))
//defer delete(converted_samples) //defer delete(converted_samples)
//for sample, i in samples { //for sample, i in frame.samples {
// converted_samples[i] = u8(sample & 0xFF) // converted_samples[i] = u8(sample & 0xFF)
//} //}
@@ -102,13 +106,6 @@ main :: proc() {
flac.md5hash(&md5_ctx, flac_data.metadata.bits_per_sample, frame.samples) flac.md5hash(&md5_ctx, flac_data.metadata.bits_per_sample, frame.samples)
} }
end := time.now()
err = flac.md5sum(&md5_ctx, flac_data)
if err == .MD5_Mismatch {
fmt.println("Decoded audio data is not correct.")
os.exit(1)
}
alsa_err = alsa.pcm_drain(handle) alsa_err = alsa.pcm_drain(handle)
if alsa_err < 0 { if alsa_err < 0 {
@@ -116,6 +113,14 @@ main :: proc() {
} }
alsa.pcm_close(handle) alsa.pcm_close(handle)
end := time.now()
err = flac.md5sum(&md5_ctx, flac_data)
if err == .MD5_Mismatch {
fmt.printfln("Decoded audio data is not correct. Expected MD5: %v, Got: %v", flac_data.metadata.expected_md5, flac_data.metadata.calculated_md5)
os.exit(1)
}
elapsed := time.diff(start, end) elapsed := time.diff(start, end)
fmt.println("Decoding took", elapsed) fmt.println("Decoding took", elapsed)
} }
-11
View File
@@ -591,10 +591,6 @@ read_next_frame :: proc(r: ^Reader, flac: ^Flac, allocator := context.allocator)
tee_r: io.Tee_Reader tee_r: io.Tee_Reader
crc_buffer: Buffer crc_buffer: Buffer
// NOTE: using the default heap allocator here causes a use-after-free bug on files subset/05, subset/06, and subset/25
// No idea what the cause of the bug is.
//
// Resolved without understanding the root issue. See below code for a note on this.
buffer_init_allocator(&crc_buffer, 0, 128) buffer_init_allocator(&crc_buffer, 0, 128)
defer buffer_destroy(&crc_buffer) defer buffer_destroy(&crc_buffer)
@@ -806,13 +802,6 @@ read_next_frame :: proc(r: ^Reader, flac: ^Flac, allocator := context.allocator)
// Frame Footer // Frame Footer
// //
crc16_bytes := buffer_to_bytes(&crc_buffer) crc16_bytes := buffer_to_bytes(&crc_buffer)
// NOTE: The order of these two calls is important. If we're using the default heap allocator
// for crc_buffer and we call read_data before calculate_crc16 then we run into a memory bug.
// I'm still not sure the root cause of the bug but it disappears when they're in this order.
//
// In the below cases the bug doesn't happen and the order doesn't matter.
// When using the temp allocator or an arena allocator.
// When using the reader from the arguments instead of the tee reader.
calculated_frame_crc := calculate_crc16(crc16_bytes) calculated_frame_crc := calculate_crc16(crc16_bytes)
frame_crc := u16(read_data(r, u16be) or_return) frame_crc := u16(read_data(r, u16be) or_return)
+2
View File
@@ -6,6 +6,7 @@ import "core:crypto/legacy/md5"
FLAC_MAGIC :: 'f' << 24 | 'L' << 16 | 'a' << 8 | 'C' FLAC_MAGIC :: 'f' << 24 | 'L' << 16 | 'a' << 8 | 'C'
//odinfmt: disable //odinfmt: disable
@(rodata)
crc8_lookup := [256]u8 { crc8_lookup := [256]u8 {
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
@@ -41,6 +42,7 @@ crc8_lookup := [256]u8 {
0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3,
} }
@(rodata)
crc16_lookup := [256]u16 { crc16_lookup := [256]u16 {
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022, 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,