Skip to content

Memory unsafety in `sub_self_call`

I caught this while working on #38 (closed). The code for sub_self_call looks something like this (simplified):

        // Get pointers to the varname and to the first subscript
        let (varname, subscripts) = self.get_buffers();
        // 1
        let t = self.subscripts.last_mut().unwrap_or(unsafe { self.variable.as_mut_vec() });
        loop {
            // pretend this is initialized to zeros, doesn't matter for this example
            let last_self_buffer: ydb_buffer_t = todo!();
            let status = unsafe {
                ydb_subscript_next_st(
                    tptoken.0,
                    &mut err_buffer_t,
                    varname.as_ptr(), // 3
                    subscripts.len() as i32,
                    subscripts.as_ptr() as *const _,
                    &mut last_self_buffer,
                )
            };

            if status == YDB_ERR_INVSTRLEN {
                t.reserve(last_self_buffer.len_used); // 2
                continue;
            }
        }

This is broken: if t is self.variable (1), then t.reserve can reallocate it (2), at which point varname.as_ptr() points to freed memory (3).

I don't yet have a test showing a double-free due to this, but I'm sure it's possible.