LINUX.ORG.RU

pure C ошибка при освобождении памяти

 


0

2

Здравствуйте, у меня есть такой код, для кривой безье

struct pt{
	GLfloat x;
	GLfloat y;
};
typedef struct pt Pt;

struct rc{
	Pt lt;
	Pt rt;
	Pt rb;
	Pt lb;
};
typedef struct rc Rc;

Pt add(Pt a,Pt b){
	Pt r;
	r.x = a.x + b.x;
	r.y = a.y + b.y;
	return r;
}

Pt sub(Pt a,Pt b){
	Pt r;
	r.x = a.x - b.x;
	r.y = a.y - b.y;
	return r;
}

Pt mul(Pt a,GLfloat k){
	Pt r;
	r.x = a.x * k;
	r.y = a.y * k;
	return r;
}

void bezier(Pt p1, Pt p2, Pt p3, GLfloat step, Pt* res){
	Pt v1,v2;
	v1 = sub(p2,p1);
	v2 = sub(p3,p2);
	GLfloat c = step;
	res[0] = p1;
	int i;
	for(i=1; c < 1; ++i, c += step){
		Pt p = add(p1,mul(v1,c));
		Pt v = sub(add(p2,mul(v2,c)),p);
		res[i] = add(p,mul(v,c));
	}
	res[i] = p3;
}
Когда я запускаю его так, то все нормально:
int main(){
	Pt arr[11];
	Pt a,b,c;
	a.x = -1;
	a.y = 0;
	b.x = 0;
	b.y = 1;
	c.x = 1;
	c.y = 0;
	bezier(a,b,c,0.1,arr);
//	bezier((double)fax,(double)fay,(double)fbx,(double)fby,(double)fcx,(double)fcy,0.1,arr);
	for(int i=0; i<11; ++i)
		printf("(%f, %f),\n",arr[i].x,arr[i].y);
	return 0;
}
А когда так, то при освобождении памяти все крашится
int main(){
	Pt *arr = malloc(sizeof(Pt) * 11);
	Pt a,b,c;
	a.x = -1;
	a.y = 0;
	b.x = 0;
	b.y = 1;
	c.x = 1;
	c.y = 0;
	bezier(a,b,c,0.1,arr);
//	bezier((double)fax,(double)fay,(double)fbx,(double)fby,(double)fcx,(double)fcy,0.1,arr);
	for(int i=0; i<11; ++i)
		printf("(%f, %f),\n",arr[i].x,arr[i].y);
	free(arr);
	return 0;
}
ошибка выглядит так:
*** glibc detected *** ./textTest: double free or corruption (out): 0x0000000000e31010 ***
textTest: malloc.c:2451: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted (core dumped)
make: *** [c] Ошибка 134
компилю gcc 4.6 без флагов оптимизации

★★★★★

Последнее исправление: cetjs2 (всего исправлений: 1)

Цикл for в функции bezier повреждает переданный фрагмент памяти на последних итерациях, free() обнаруживает поврежденный canary guard и крашится.

rand
()
Ответ на: комментарий от rand

Я увеличил размер выделяемого блока, и проблема пропала. Но я все равно не понимаю проблему, ведь во время исполнения я не получаю ошибку о выходе за границу массива.

Aswed ★★★★★
() автор топика
Ответ на: комментарий от Aswed

во время исполнения я не получаю ошибку о выходе за границу массива

Welcome to C

Во времена турбо си можно было долго не замечать никаких ошибок.

greenman ★★★★★
()
Последнее исправление: greenman (всего исправлений: 1)
Ответ на: комментарий от Aswed

Да, действительно, ошибки нет. Запустил у себя, все запустилось без проблем:

$ gcc -Wall 1.c -o 1 -std=c99 -ggdb && ./1
(-1.000000, 0.000000),
(-0.800000, 0.180000),
(-0.600000, 0.320000),
(-0.400000, 0.420000),
(-0.200000, 0.480000),
(0.000000, 0.500000),
(0.200000, 0.480000),
(0.400000, 0.420000),
(0.600000, 0.320000),
(0.800000, 0.180000),
(1.000000, 0.000000),
$ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Может, у вас там еще какой-то код есть?

rand
()
Ответ на: комментарий от Aswed

В смысле повреждает? Можно по подробнее о проблеме и как ее решить, пожалуйста.

0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 не равно 1.0, поэтому последняя итерация цикла происходит не с i==10, а i==11.

i-rinat ★★★★★
()

а если так: Pt *arr = (Pt*) malloc(sizeof(Pt) * 11);

rimsleur
()
Ответ на: комментарий от rand

Есть, но он не важен, поскольку ошибка вылезала, если использовать только то, что здесь.

Aswed ★★★★★
() автор топика

for(i=1; c < 1; ++i, c += step){

никогда не нужно сравнивать на равенство дробные числа.

i-rinat верно сказал, что сумма дробей не обязана вычисляться абсолютно точно. В данном случае я-бы сделал массив побольше, с тем расчётом, что может возникнуть ошибка округления.

И да, никаких «out of range» в pure C нет. Нет проверок, так оно быстрее.

drBatty ★★
()

во вторых у тебя ++i, а нужно i++

и в третьих так:

for(int i=0; i<11; i++)
{
  Pt *pt1 = (Pt*) arr + i;
  printf("(%f, %f),\n",pt1->x,pt->y);
}

rimsleur
()
Ответ на: комментарий от rimsleur

у тебя ++i, а нужно i++

Не нужно. В данном случае монопенисуально.

akk ★★★★★
()
Ответ на: комментарий от rimsleur

Pt *arr = (Pt*) malloc(sizeof(Pt) * 11);

типы указателей С умеет приводить сам

Pt *pt1 = (Pt*) arr + i;
printf("(%f, %f),\n",pt1->x,pt->y)

это тоже самое, что и arr[i].x только более громоздко

во вторых у тебя ++i, а нужно i++

не разводите холивар

Aswed ★★★★★
() автор топика
Ответ на: комментарий от drBatty

Спасибо, я не знал, что С не выдает никаких ошибок даже если писать в чужую память, а не читать из нее.

Aswed ★★★★★
() автор топика
Ответ на: комментарий от Aswed

об этом расскажет:

$ valgrind ./textTest

anonymous
()
Ответ на: комментарий от rimsleur

во вторых у тебя ++i, а нужно i++

в pure C без разницы.

drBatty ★★
()
Ответ на: комментарий от Aswed

что С не выдает никаких ошибок даже если писать в чужую память, а не читать из нее.

вообще НИКОГДА не выдаёт. Сегфолт выдаст сама OS, если ты заберёшься куда-то очень далеко (на неиспользуемую страницу). А в коде _вообще_ нет никаких проверок. a тоже самое, что и *(a+i)

ЗЫЖ i[a] тоже работает.

drBatty ★★
()
Ответ на: комментарий от Aswed

я не знал, что для циклов разницы нет. так что написал с пользой для себя)

rimsleur
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.