eteran / c-vector

A dynamic array implementation in C similar to the one found in standard C++

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Putting cvector_push_back in a function causes undefined behaviour

TVKain opened this issue · comments

#include "cvector.h"
#include <stdio.h>

void foo(cvector_vector_type(int) *v)
{
	cvector_vector_type(int) tmp = *v;
	for (int i = 0; i < 100; ++i) {
		cvector_push_back(tmp, i);
	}
}

int main()
{
	cvector_vector_type(int) v = NULL;

	cvector_push_back(v, 1);
	foo(&v);

	printf("Size: %zu", cvector_size(v));

	return 0;
}

The out put of the code above is:

Size: 101

But when i increase the loop count to 1000

#include "cvector.h"
#include <stdio.h>

void foo(cvector_vector_type(int) *v)
{
	cvector_vector_type(int) tmp = *v;
	for (int i = 0; i < 1000; ++i) {
		cvector_push_back(tmp, i);
	}
}

int main()
{
	cvector_vector_type(int) v = NULL;

	cvector_push_back(v, 1);
	foo(&v);

	printf("Size: %zu", cvector_size(v));

	return 0;
}

The output is:

Size: 1854881427984

Also if I don't put the line cvector_push_back(v, 1); in main to initialize it then the output is:

Size: 0

I suspect memory leaks happen if cvector_push_back is used in another function

I just added *v = tmp; at the end of your function and the output is Size: 1001

void foo(cvector_vector_type(int) *v) 
{
    cvector_vector_type(int) tmp = *v;
    for (int i = 0; i < 1000; ++i) {
        cvector_push_back(tmp, i);
    }
    *v = tmp;
}

tested with 1000000000 elements

With *v = tmp;

void foo(cvector_vector_type(int) *v) 
{
    cvector_vector_type(int) tmp = *v;
    for (int i = 0; i < 1000000000; ++i) {
        cvector_push_back(tmp, i);
    }
    *v = tmp;
}

Output:

image

Without *v = tmp;

void foo(cvector_vector_type(int) *v) 
{
    cvector_vector_type(int) tmp = *v;
    for (int i = 0; i < 1000000000; ++i) {
        cvector_push_back(tmp, i);
    }
}

Output:

image

Direct access

void foo(cvector_vector_type(int) *v) 
{
    for (int i = 0; i < 1000000000; ++i) {
        cvector_push_back((*v), i);
    }
}

Note: using (*v) not *v

Output:

image

Might be good to add a test for this once @eteran the maintainer has had a chance to review the pending PRs...

@TVKain Yea, because it's not "real objects", it does get a little funky when trying to create a vector in one function and then modifying it in another.

I certainly could update the documentation to mention the pitfalls, but it basically boils down to the macros editing the functions LOCAL variable on some resizes, which does not update the pointer in the caller's scope.

@K4zoku has identified this quirk and his recomendation is exactly what I would have said.

@andy5995 yup, the end of the year is a bit super busy because everyone at the office is trying to be productive before we all disappear for the holidays ;-). I'll definitely get through the pending PRs soon though!