fix: get rid of a use-after-free bug that happens when using the default heap allocator

This commit is contained in:
2024-06-20 05:00:35 +02:00
parent 3c482fc63a
commit 5e23cc8f58
5 changed files with 74 additions and 30 deletions
-4
View File
@@ -4,11 +4,7 @@ Files:-
if they are, then the blocking strategy is VARIABLE, if not, then it's FIXED. if they are, then the blocking strategy is VARIABLE, if not, then it's FIXED.
Playback issues in the example program that may relate to the decoder:- Playback issues in the example program that may relate to the decoder:-
05 - CRC fails for a frame. The gotten CRC is different each time, expected CRC is also different sometimes.
06 - Same as above
23 - Crunchy loud noise mixed with the actual audio data 23 - Crunchy loud noise mixed with the actual audio data
25 - Same CRC problem
It's worth noting that if we get rid of the CRC checks the files play just fine.
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.
+48
View File
@@ -0,0 +1,48 @@
package flac
import "core:io"
// Buffer is a very minimal writable buffer based on bytes.Buffer
Buffer :: struct {
buf: [dynamic]byte,
}
buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator, loc := #caller_location) {
b.buf = make([dynamic]byte, len, cap, allocator, loc)
}
buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
return append(&b.buf, ..p), nil
}
buffer_destroy :: proc(b: ^Buffer) {
delete(b.buf)
}
buffer_to_bytes :: proc(b: ^Buffer) -> []byte {
return b.buf[:]
}
buffer_to_stream :: proc(b: ^Buffer) -> (s: io.Stream) {
s.data = b
s.procedure = _buffer_proc
return
}
@(private)
_buffer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
b := (^Buffer)(stream_data)
#partial switch mode {
case .Write:
return io._i64_err(buffer_write(b, p))
case .Size:
n = i64(cap(b.buf))
return
case .Destroy:
buffer_destroy(b)
return
case .Query:
return io.query_utility({.Write, .Size, .Destroy})
}
return 0, .Empty
}
+10 -11
View File
@@ -17,6 +17,7 @@ main :: proc() {
fmt.eprintln("Please provide a path to a flac file.") fmt.eprintln("Please provide a path to a flac file.")
os.exit(1) os.exit(1)
} }
defer delete(os.args)
arena: virtual.Arena arena: virtual.Arena
handle: ^alsa.pcm_t handle: ^alsa.pcm_t
@@ -53,12 +54,10 @@ main :: proc() {
sample_rate := flac_data.metadata.sample_rate sample_rate := flac_data.metadata.sample_rate
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)
defer delete(frame.samples)
if err != nil { if err != nil {
if err == .EOF { if err == .EOF {
break break
@@ -99,15 +98,15 @@ main :: proc() {
} }
fmt.printfln("Played %d frames", frames) fmt.printfln("Played %d frames", frames)
//flac.md5hash(&md5_ctx, flac_data.metadata.bits_per_sample, samples) flac.md5hash(&md5_ctx, flac_data.metadata.bits_per_sample, frame.samples)
} }
end := time.now() end := time.now()
//err = flac.md5sum(&md5_ctx, flac_data) err = flac.md5sum(&md5_ctx, flac_data)
//if err == .MD5_Mismatch { if err == .MD5_Mismatch {
// fmt.println("Decoded audio data is not correct.") fmt.println("Decoded audio data is not correct.")
// os.exit(1) os.exit(1)
//} }
alsa_err = alsa.pcm_drain(handle) alsa_err = alsa.pcm_drain(handle)
if alsa_err < 0 { if alsa_err < 0 {
+6 -7
View File
@@ -16,6 +16,7 @@ main :: proc() {
fmt.eprintln("Please provide a path to a flac file.") fmt.eprintln("Please provide a path to a flac file.")
os.exit(1) os.exit(1)
} }
defer delete(os.args)
handle: ^alsa.pcm_t handle: ^alsa.pcm_t
@@ -61,14 +62,12 @@ main :: proc() {
converted_samples[i] = i16(new_sample) converted_samples[i] = i16(new_sample)
} }
for { frames := alsa.pcm_writei(handle, raw_data(converted_samples), u64(len(flac_data.samples)) / u64(flac_data.metadata.channels))
frames := alsa.pcm_writei(handle, raw_data(converted_samples), u64(len(flac_data.samples)) / u64(flac_data.metadata.channels)) if frames < 0 {
if frames < 0 { fmt.eprintln("Error writing to PCM device:", alsa.strerror(auto_cast frames))
fmt.eprintln("Error writing to PCM device:", alsa.strerror(auto_cast frames)) return
break
}
fmt.printfln("Played %d frames", frames)
} }
fmt.printfln("Played %d frames", frames)
alsa_err = alsa.pcm_drain(handle) alsa_err = alsa.pcm_drain(handle)
if alsa_err < 0 { if alsa_err < 0 {
+10 -8
View File
@@ -852,15 +852,17 @@ read_metadata :: proc(r: ^Reader, buffered := false, allocator := context.alloca
return flac, nil return flac, nil
} }
read_next_frame :: proc(r: ^Reader, flac: ^Flac) -> (frame: Frame, err: Error) { read_next_frame :: proc(r: ^Reader, flac: ^Flac, allocator := context.allocator) -> (frame: Frame, err: Error) {
// //
// Frame Header // Frame Header
// //
context.allocator = allocator
tee_r: io.Tee_Reader tee_r: io.Tee_Reader
crc_buffer: bytes.Buffer
bytes.buffer_init_allocator(&crc_buffer, 0, 128) crc_buffer: Buffer
defer bytes.buffer_destroy(&crc_buffer) buffer_init_allocator(&crc_buffer, 0, 128, context.temp_allocator)
crc := bytes.buffer_to_stream(&crc_buffer)
crc := buffer_to_stream(&crc_buffer)
r := &Reader{ r := &Reader{
r = io.tee_reader_init(&tee_r, r, crc), r = io.tee_reader_init(&tee_r, r, crc),
buf = r.buf, buf = r.buf,
@@ -960,7 +962,7 @@ read_next_frame :: proc(r: ^Reader, flac: ^Flac) -> (frame: Frame, err: Error) {
// TODO: sample rate MUST NOT be 0 if the subframe contains audio. // TODO: sample rate MUST NOT be 0 if the subframe contains audio.
// a sample rate of 0 MAY be used when non-audio is represented. // a sample rate of 0 MAY be used when non-audio is represented.
crc8_bytes := bytes.buffer_to_bytes(&crc_buffer) crc8_bytes := buffer_to_bytes(&crc_buffer)
frame_header_crc := u8(read_bits(r, 8) or_return) frame_header_crc := u8(read_bits(r, 8) or_return)
calculated_header_crc := calculate_crc8(crc8_bytes) calculated_header_crc := calculate_crc8(crc8_bytes)
@@ -1064,7 +1066,7 @@ read_next_frame :: proc(r: ^Reader, flac: ^Flac) -> (frame: Frame, err: Error) {
// //
// Frame Footer // Frame Footer
// //
crc16_bytes := bytes.buffer_to_bytes(&crc_buffer) crc16_bytes := buffer_to_bytes(&crc_buffer)
frame_crc := u16(read_data(r, u16be) or_return) frame_crc := u16(read_data(r, u16be) or_return)
calculated_frame_crc := calculate_crc16(crc16_bytes) calculated_frame_crc := calculate_crc16(crc16_bytes)
@@ -1101,7 +1103,7 @@ md5hash :: proc(md5_ctx: ^md5.Context, bps: u8, samples: []i32) {
} }
md5sum :: proc(md5_ctx: ^md5.Context, flac: ^Flac) -> Error { md5sum :: proc(md5_ctx: ^md5.Context, flac: ^Flac) -> Error {
calculated_md5: [16]byte calculated_md5 := [16]byte{}
md5.final(md5_ctx, calculated_md5[:]) md5.final(md5_ctx, calculated_md5[:])
flac.metadata.calculated_md5 = calculated_md5 flac.metadata.calculated_md5 = calculated_md5