mirror of
https://github.com/IllusionMan1212/flac-odin.git
synced 2026-10-24 02:12:29 +00:00
fix: get rid of a use-after-free bug that happens when using the default heap allocator
This commit is contained in:
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
fmt.printfln("Played %d frames", frames)
|
||||
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))
|
||||
return
|
||||
}
|
||||
fmt.printfln("Played %d frames", frames)
|
||||
|
||||
alsa_err = alsa.pcm_drain(handle)
|
||||
if alsa_err < 0 {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user