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.
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
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/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.")
os.exit(1)
}
defer delete(os.args)
arena: virtual.Arena
handle: ^alsa.pcm_t
@@ -53,12 +54,10 @@ main :: proc() {
sample_rate := flac_data.metadata.sample_rate
channels := flac_data.metadata.channels
//md5_ctx: md5.Context
//md5.init(&md5_ctx)
md5_ctx: md5.Context
md5.init(&md5_ctx)
for {
frame, err := flac.read_next_frame(reader, flac_data)
defer delete(frame.samples)
frame, err := flac.read_next_frame(reader, flac_data, allocator)
if err != nil {
if err == .EOF {
break
@@ -99,15 +98,15 @@ main :: proc() {
}
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()
//err = flac.md5sum(&md5_ctx, flac_data)
//if err == .MD5_Mismatch {
// fmt.println("Decoded audio data is not correct.")
// os.exit(1)
//}
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)
if alsa_err < 0 {
+2 -3
View File
@@ -16,6 +16,7 @@ main :: proc() {
fmt.eprintln("Please provide a path to a flac file.")
os.exit(1)
}
defer delete(os.args)
handle: ^alsa.pcm_t
@@ -61,14 +62,12 @@ main :: proc() {
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))
if frames < 0 {
fmt.eprintln("Error writing to PCM device:", alsa.strerror(auto_cast frames))
break
return
}
fmt.printfln("Played %d frames", frames)
}
alsa_err = alsa.pcm_drain(handle)
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
}
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
//
context.allocator = allocator
tee_r: io.Tee_Reader
crc_buffer: bytes.Buffer
bytes.buffer_init_allocator(&crc_buffer, 0, 128)
defer bytes.buffer_destroy(&crc_buffer)
crc := bytes.buffer_to_stream(&crc_buffer)
crc_buffer: Buffer
buffer_init_allocator(&crc_buffer, 0, 128, context.temp_allocator)
crc := buffer_to_stream(&crc_buffer)
r := &Reader{
r = io.tee_reader_init(&tee_r, r, crc),
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.
// 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)
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
//
crc16_bytes := bytes.buffer_to_bytes(&crc_buffer)
crc16_bytes := buffer_to_bytes(&crc_buffer)
frame_crc := u16(read_data(r, u16be) or_return)
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 {
calculated_md5: [16]byte
calculated_md5 := [16]byte{}
md5.final(md5_ctx, calculated_md5[:])
flac.metadata.calculated_md5 = calculated_md5