segfault in empty function

I have a fairly large codebase, so pinpointing this error is probably quite difficult, but I'll try anyway. I'm getting this error from gdb:

Program received signal SIGSEGV, Segmentation fault.
0x0804f732 in Sampler::~Sampler() ()


The sampler destructor looks like this:
1
2
Sampler::~Sampler(void) {
}


Sampler has 6 subclasses, all of which also have empty destructors. I know this is probably not enough info, but the code for all of these would be too large to post. Is there anything that's obviously wrong here?


We need to see more code. If you can't post it here, you can upload the files somewhere and give us a link.
Ok, I've tried to make a selection that would be useful: http://pastebin.com/vK9bcqcN It's quite long, so I won't hold it against you if you don't want to read it:p
Can we see your main and your headers too?
Does the problem only occur when a Jittered object is destroyed?
Does it occur when an object of any subclass of Sampler is destroyed?
Last edited on
Here are the headers for Sampler and Jittered, but there are also other subclasses similar to Jittered, with different implementations of the generate_samples function: http://pastebin.com/NALuNZ44

This is the function that crashes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void Renderer::render(void) {
	std::cout << "ROFL";
	world->vp.hres = x_res->value();
	world->vp.vres = y_res->value();
	world->vp.num_samples = aa_samples->value();
	world->build();
	if (aa_check->isChecked()) {
		switch(aa_method_box->currentIndex()) {
			case 0:
				world->vp.set_sampler(new Regular(world->vp.num_samples));
				break;
			case 1:
				world->vp.set_sampler(new Random(world->vp.num_samples));
				break;
			case 2:
				world->vp.set_sampler(new Jittered(world->vp.num_samples));
				break;
			case 3:
				world->vp.set_sampler(new NRooks(world->vp.num_samples));
				break;
			case 4:
				world->vp.set_sampler(new Hammersley(world->vp.num_samples));
				break;
			default:
				world->vp.set_sampler(new Regular(world->vp.num_samples));
				break;
		}
	} else {
		world->vp.set_sampler(new Regular(1));
	}
	switch(camera_type_box->currentIndex()) {
		case 0:
			world->render_perspective();
			break;
		case 1:
			world->render_scene();
			break;
		default:
			world->render_scene();
			break;
	}
}


I only added the cout<<"ROFL" to see if anything in the function happened, but not even the ROFL is printed out.

EDIT: main is only for setup for the Qt toolkit, and not relevant here
Last edited on
fafner wrote:
I only added the cout<<"ROFL" to see if anything in the
function happened, but not even the ROFL is printed out.

Well, if you don't see ROFL, this is not the function that crashes.

Based on the message from gdb and the fact that your destructor is virtual,
my guess is that something overwrites the vtable of your objects.

I tried to recreate the problem here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;

struct Base
{
    int data[5];

    //no crash if you comment this out
    virtual ~Base() {}
};

struct Derived : public Base {};

int main()
{
    Base * b=new Derived;

    const int range=10;

    for (int i=-range; i<range; i++)
        b->data[i]=0;

    cout << "hit enter to crash";
    cin.get();

    //no crash if you comment this out
    delete b;

    return 0;
}

The for loop overwrites the vtable pointer that points to the destructor,
so, when the time comes for the destructor to be called... BOOM!

Can you spot any part of your code that might behave like this?
I just noticed this. Remember that reserve and resize don't do the same thing.
There are points where you use the former while, I believe, you intend to use the latter.

e.g. disk_samples.reserve(size); in void Sampler::map_samples_to_unit_disk(void)

http://cplusplus.com/reference/stl/vector/reserve/
http://cplusplus.com/reference/stl/vector/resize/
Last edited on
I thought about that ("ROFL") too, but the thing is that the render function is linked to a Qt button, and when the button is clicked, the program crashes immediately, without printing it out.

So what I should look for is if some of the subclasses of Sampler might have values "out of bounds" that might overwrite the vtable? I'll take a close look now and get back to you. Thanks for all your help so far!

EDIT: I tried to comment out all the map_to functions, because they aren't being called anywhere yet, and the same thing happens. Also it is worth mentioning that all the Sampler subclasses worked fine up until some point yesterday. I've tried to retrace my steps and comment out any changes that I did to make this error happen, but no luck yet:(
Last edited on
Have you run it under valgrind? It often provides helpful clues, if you're writing over memory that you shouldn't.
I've actually never used valgrind until now, seems quite awesome! Here's the output, I'm not quite sure what to make of it:

==12584== Memcheck, a memory error detector
==12584== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==12584== Using Valgrind-3.7.0.SVN and LibVEX; rerun with -h for copyright info
==12584== Command: ./ftrace
==12584== 
==12584== Conditional jump or move depends on uninitialised value(s)
==12584==    at 0x804EDD0: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:33)
==12584==    by 0x80495B4: main (main.cpp:7)
==12584==  Uninitialised value was created by a stack allocation
==12584==    at 0x8049574: main (main.cpp:5)
==12584== 
==12584== Conditional jump or move depends on uninitialised value(s)
==12584==    at 0x804EDDA: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:34)
==12584==    by 0x80495B4: main (main.cpp:7)
==12584==  Uninitialised value was created by a stack allocation
==12584==    at 0x8049574: main (main.cpp:5)
==12584== 
==12584== Use of uninitialised value of size 4
==12584==    at 0x804EDE2: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:34)
==12584==    by 0x80495B4: main (main.cpp:7)
==12584==  Uninitialised value was created by a stack allocation
==12584==    at 0x8049574: main (main.cpp:5)
==12584== 
==12584== Invalid read of size 4
==12584==    at 0x804EDE7: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:34)
==12584==    by 0x80495B4: main (main.cpp:7)
==12584==  Address 0x4 is not stack'd, malloc'd or (recently) free'd
==12584== 
==12584== 
==12584== Process terminating with default action of signal 11 (SIGSEGV)
==12584==  Access not within mapped region at address 0x4
==12584==    at 0x804EDE7: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:34)
==12584==    by 0x80495B4: main (main.cpp:7)
==12584==  If you believe this happened as a result of a stack
==12584==  overflow in your program's main thread (unlikely but
==12584==  possible), you can try to increase the size of the
==12584==  main thread stack using the --main-stacksize= flag.
==12584==  The main thread stack size used in this run was 8388608.
==12584== 
==12584== HEAP SUMMARY:
==12584==     in use at exit: 1,728 bytes in 3 blocks
==12584==   total heap usage: 4 allocs, 1 frees, 1,732 bytes allocated
==12584== 
==12584== LEAK SUMMARY:
==12584==    definitely lost: 0 bytes in 0 blocks
==12584==    indirectly lost: 0 bytes in 0 blocks
==12584==      possibly lost: 0 bytes in 0 blocks
==12584==    still reachable: 1,728 bytes in 3 blocks
==12584==         suppressed: 0 bytes in 0 blocks
==12584== Reachable blocks (those to which a pointer was found) are not shown.
==12584== To see them, rerun with: --leak-check=full --show-reachable=yes
==12584== 
==12584== For counts of detected and suppressed errors, rerun with: -v
==12584== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 17 from 6)
Segmentation fault



It seems to me that the Sampler subclass instance that's being passed to ViewPlane::set_sampler somehow isn't initialized?
Sorry to post twice in a row here, but I found something else by playing around a bit more with valgrind:


==13006== Memcheck, a memory error detector
==13006== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==13006== Using Valgrind-3.7.0.SVN and LibVEX; rerun with -h for copyright info
==13006== Command: ./ftrace
==13006== 
==13006== Conditional jump or move depends on uninitialised value(s)
==13006==    at 0x804EDD0: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:33)
==13006==    by 0x80495B4: main (main.cpp:7)
==13006==  Uninitialised value was created by a stack allocation
==13006==    at 0x8049574: main (main.cpp:5)
==13006== 
==13006== Conditional jump or move depends on uninitialised value(s)
==13006==    at 0x804EDDA: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:34)
==13006==    by 0x80495B4: main (main.cpp:7)
==13006==  Uninitialised value was created by a stack allocation
==13006==    at 0x8049574: main (main.cpp:5)
==13006== 
==13006== Use of uninitialised value of size 4
==13006==    at 0x804EDE2: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:34)
==13006==    by 0x80495B4: main (main.cpp:7)
==13006==  Uninitialised value was created by a stack allocation
==13006==    at 0x8049574: main (main.cpp:5)
==13006== 
==13006== Invalid read of size 4
==13006==    at 0x804EDE7: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:34)
==13006==    by 0x80495B4: main (main.cpp:7)
==13006==  Address 0x4 is not stack'd, malloc'd or (recently) free'd
==13006== 
==13006== 
==13006== Process terminating with default action of signal 11 (SIGSEGV)
==13006==  Access not within mapped region at address 0x4
==13006==    at 0x804EDE7: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:34)
==13006==    by 0x80495B4: main (main.cpp:7)
==13006==  If you believe this happened as a result of a stack
==13006==  overflow in your program's main thread (unlikely but
==13006==  possible), you can try to increase the size of the
==13006==  main thread stack using the --main-stacksize= flag.
==13006==  The main thread stack size used in this run was 8388608.
==13006== 
==13006== HEAP SUMMARY:
==13006==     in use at exit: 1,728 bytes in 3 blocks
==13006==   total heap usage: 4 allocs, 1 frees, 1,732 bytes allocated
==13006== 
==13006== 68 bytes in 1 blocks are still reachable in loss record 1 of 3
==13006==    at 0x402745D: operator new(unsigned int) (vg_replace_malloc.c:255)
==13006==    by 0x804958E: main (main.cpp:7)
==13006== 
==13006== 332 bytes in 1 blocks are still reachable in loss record 2 of 3
==13006==    at 0x402745D: operator new(unsigned int) (vg_replace_malloc.c:255)
==13006==    by 0x804D153: __gnu_cxx::new_allocator<int>::allocate(unsigned int, void const*) (new_allocator.h:89)
==13006==    by 0x804CC1B: std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned int) (in /home/terry/Dev/FTrace-noGUI/ftrace)
==13006==    by 0x804C1BC: int* std::vector<int, std::allocator<int> >::_M_allocate_and_copy<int*>(unsigned int, int*, int*) (stl_vector.h:967)
==13006==    by 0x804B944: std::vector<int, std::allocator<int> >::reserve(unsigned int) (vector.tcc:74)
==13006==    by 0x804AF6F: Sampler::setup_shuffled_indices() (Sampler.cpp:32)
==13006==    by 0x804AD1A: Sampler::Sampler(int) (Sampler.cpp:18)
==13006==    by 0x804A726: Regular::Regular(int) (Regular.cpp:11)
==13006==    by 0x80495A2: main (main.cpp:7)
==13006== 
==13006== 1,328 bytes in 1 blocks are still reachable in loss record 3 of 3
==13006==    at 0x402745D: operator new(unsigned int) (vg_replace_malloc.c:255)
==13006==    by 0x80493B1: __gnu_cxx::new_allocator<Point2D>::allocate(unsigned int, void const*) (new_allocator.h:89)
==13006==    by 0x804923B: std::_Vector_base<Point2D, std::allocator<Point2D> >::_M_allocate(unsigned int) (in /home/terry/Dev/FTrace-noGUI/ftrace)
==13006==    by 0x804BF0C: Point2D* std::vector<Point2D, std::allocator<Point2D> >::_M_allocate_and_copy<Point2D*>(unsigned int, Point2D*, Point2D*) (stl_vector.h:967)
==13006==    by 0x804B6E4: std::vector<Point2D, std::allocator<Point2D> >::reserve(unsigned int) (vector.tcc:74)
==13006==    by 0x804AD0F: Sampler::Sampler(int) (Sampler.cpp:17)
==13006==    by 0x804A726: Regular::Regular(int) (Regular.cpp:11)
==13006==    by 0x80495A2: main (main.cpp:7)
==13006== 
==13006== LEAK SUMMARY:
==13006==    definitely lost: 0 bytes in 0 blocks
==13006==    indirectly lost: 0 bytes in 0 blocks
==13006==      possibly lost: 0 bytes in 0 blocks
==13006==    still reachable: 1,728 bytes in 3 blocks
==13006==         suppressed: 0 bytes in 0 blocks
==13006== 
==13006== For counts of detected and suppressed errors, rerun with: -v
==13006== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 17 from 6)
Segmentation fault

Last edited on
Valgrind wrote:

Process terminating with default action of signal 11 (SIGSEGV)
Access not within mapped region at address 0x4
at 0x804EDE7: ViewPlane::set_sampler(Sampler*) (ViewPlane.cpp:34)
by 0x80495B4: main (main.cpp:7)


That address value looks very low (four bytes beyond null); first guess, there's a null pointer somewhere, and you're using it as if it were a fully formed object.

All the complaints involve ViewPlane::set_sampler, which accepts a pointer from what I can tell. Is that pointer definitely good?
Last edited on
Wow, that is low:p The call to set_sampler is like this:
w.vp.set_sampler(new Regular(1));

The Regular constructor called is:
1
2
3
Regular::Regular(int ns) : Sampler(ns) {
	generate_samples();
}


Which again calls the Sampler constructor:
1
2
3
4
5
Sampler::Sampler(int ns) : num_samples(ns), num_sets(83),
			count(0), jump(0) {
	samples.reserve(num_samples * num_sets);
	setup_shuffled_indices();
}


As far as I can see that pointer should be fine?
No need to guess; stick some printlines in the code and see what actual values are being used :)

Conditional jump or move depends on uninitialised value(s)


This generally means that somewhere there is an if or a while or a for or some other kind of decision branch, where the decision is being made based on the contents of memory that you have never put a value into.
Last edited on
Ok, I edited the code a little, to this:
1
2
3
Regular *r = new Regular(16);
	std::cout << r->get_num_samples() << "\t" << (int)sizeof(Regular);
	w.vp.set_sampler(r);


If I comment out the last line, it prints out 16 and 68. If I dont comment it out, it prints out nothing:p EDIT: AND crashes

EDIT2: Ok, I checked every loop in use in both Sampler and Regular, and they both seem fine.
Last edited on
You know what, I'm gonna just rewrite all of my sampler classes. Thanks for all your help! And thanks for introducing me to valgrind:)
Do ViewPlane's constructors set sampler_ptr to zero?
Last edited on
That's exactly what they don't! I figured it out while I was rewriting, the reason I had left it out was because the viewPlane class was written quite a while before the sampler class, and I just forgot about it. Thanks so much for your help!
Topic archived. No new replies allowed.