Skip to content

FP in UseAfterFree with reallocating data structures #20577

@novafacing

Description

@novafacing

Description of the false positive

UseAfterFree.ql raises a false positive when run on a data structure with reallocated internal storage. I've observed with in several different data structure implementations, but the example below triggers the FP.

typedef unsigned long long size_t;

template<class T> class Foo {
    public:
        Foo(void): capacity(0), size(0), items(nullptr) {}

        ~Foo(void) { Clear(); }

        void Clear(void) {
            if (items != nullptr) {
                delete[] items;
                items = nullptr;
                size = 0;
                capacity = 0;
            }
        }

        T *Set(size_t index, T *item) {
            if (index >= capacity) {
                size_t new_capacity = capacity == 0 ? 4 : capacity;
                while (index >= new_capacity) {
                    new_capacity *= 2;
                }
                T **new_items = new T *[new_capacity];
                for (size_t i = 0; i < size; i++) {
                    new_items[i] = items[i];
                }
                if (items != nullptr) {
                    delete[] items;
                }
                items = new_items;
                capacity = new_capacity;
            }

            if (index >= size) {
                for (size_t i = size; i < index; i++) {
                    items[i] = nullptr;
                }
                size = index + 1;
            }

            items[index] = item;
            return item;
        }

        T *Insert(size_t index, T *item) {
            for (size_t i = index; i < size; i++) {
                if (Set(i + 1, Get(i))) {
                    return nullptr;
                }
            }
            return Set(index, item);
        }

        T *Get(size_t index) {
            if (size <= index) {
                return nullptr;
            }
            return items[index];
        }


    protected:
        size_t capacity;
        size_t size;
        T **items;
};

int main() {
    Foo<size_t> foo;
    foo.Set(1024, new size_t(44));
    foo.Clear();
    foo.Insert(1025, new size_t(46));
    foo.Get(1025);
    return 0;
}

To save anyone else the effort, this does not actually have a UAF exercised according to ASAN :)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions