Reputation: 1
I'm having trouble tracking down the cause of a segfault (no core dump).
When assigning a values (from another variable) to *trans_theta
, *trans_x
, or *trans_y
, my program gives a segfault when I close the GUI window. Backtrace gives a series of g_xxx
, gdk_xxx
, and gtk_xxx
functions. Simply getting rid of these lines eliminates the fault.
Program exits normally if I only close the GUI window (no click data).
I've used this same method in multiple functions with struct members under the same or similar umbrella - this makes me think I've got some fundamental misunderstanding of GTK or memory.
Here's the header file:
#include <gtk/gtk.h>
#ifndef _ROVER_GUI
#define _ROVER_GUI
#define WINDOW_CTR_X 220
#define WINDOW_CTR_Y 220
#define MIN_RADIUS 20
#define PI 3.1415926535897932382646
#define WHEEL_ANGLE 0.7853981633974483096156 // PI/4
typedef struct gui_obj{
GtkBuilder * builder;
GtkWidget * window;
GtkWidget * img;
GdkPixbuf * icon;
GError * error;
} s_gui;
typedef struct point_obj{
int x; // x-coordinate of point
int y; // y-coordinate of point
double theta; // Angle of (x,y), +/- pi (+/- 180 degrees)
double mag; // Magnitude (hypotenuse) of (x,y)
} s_point;
typedef struct data_obj{
// GUI INPUTS
// **********
// Coordinates of mouse pointer on click (relative to window origin)
// and coordinates of window center (relative to window origin)
s_point ptr_loc;
s_point ctr_loc;
s_point delta; // Vector from window center to pointer
s_point trans; // s_delta translated to wheel coordinates
} s_data;
#endif
And here's the program file:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <limits.h>
#include <gtk/gtk.h>
#include <pthread.h>
#include "rover_gui.h"
// Function to calculate vector
int calcVector( int * x1, int * y1, int * x2, int * y2, int * dx, int * dy )
{
// Calculate vector from point 1 to point 2
*dx = *x2 - *x1;
*dy = *y2 - *y1;
return 0;
}
// Function to correct y-dir portion of vector (screen coords to cartesian)
int correctVector( int * dx, int * dy, double * angle, double * magnitude )
{
// Invert dy coordinate
*dy = -(*dy);
// Calculate magnitude and assign value
double mag = pow( (*dx)*(*dx) + (*dy)*(*dy), 0.5 );
// Calculate angle and assign value
double theta;
if( mag == 0.0 ){
theta = 0.0;
}
else{
theta = acos( (*dx) / pow( (*dx)*(*dx) + (*dy)*(*dy), 0.5 ) ); // Calculate angle
}
*magnitude = mag; // Set input point value
*angle = theta;
return 0;
}
// Calculate motor outputs
int calcVectorInWheelSystem( double * mag, double * theta,
int * trans_x, int * trans_y,
double * trans_mag, double * trans_theta )
{
// Transform input vector to wheel coordinate system
double new_mag = *mag;
double new_theta;
if( ((*theta) < -.75*PI) && ((*theta) > -PI) ){ // From -135 to -180 deg
new_theta = (PI + *theta) + PI - WHEEL_ANGLE; // in radians
}
else{
new_theta = *theta - WHEEL_ANGLE; // in radians
}
int new_x;
int new_y;
new_x = (int)(new_mag * cos( new_theta ));
new_y = (int)(new_mag * sin( new_theta ));
*trans_mag = new_mag;
*trans_theta = new_theta;
*trans_x = new_x;
*trans_y = new_y;
return 0;
}
// Function to print out coordinates received from gtk_main() events
void takeItAway( s_data * sp_data )
{
// USE input coordinates to calculate directional vector
int ret = 0;
ret = calcVector(&(sp_data->ctr_loc.x), &(sp_data->ctr_loc.y),
&(sp_data->ptr_loc.x), &(sp_data->ptr_loc.y),
&(sp_data->delta.x), &(sp_data->delta.y) );
if( ret != 0 ){
printf( "Failed in calcVector.\n" );
}
// CORRECT y-coordinate (invert)
ret = correctVector( &(sp_data->delta.x), &(sp_data->delta.y),
&(sp_data->delta.theta), &(sp_data->delta.mag) );
if( ret != 0 ){
printf( "Failed in correctVector.\n" );
}
// CONVERT input vector to Wheel System coordinates
ret = calcVectorInWheelSystem( &(sp_data->delta.mag), &(sp_data->delta.theta),
&(sp_data->trans.x), &(sp_data->trans.y),
&(sp_data->trans.mag), &(sp_data->trans.theta) );
if( ret != 0 ){
printf( "Failed in calcVectorInWheelSystem.\n" );
}
}
// Function to initialize GUI
int initGUI( s_gui * p_gui, int * arg_num, char ** arg_vec[] )
{
// Initialize error to NULL, initialize GTK
p_gui->error = NULL;
gtk_init( arg_num, arg_vec );
// Initialize Builder object and use it to create the gui from the glade file
p_gui->builder = gtk_builder_new( );
if( !gtk_builder_add_from_file( p_gui->builder, "rover_gui.glade", &p_gui->error ) ){
g_warning( "%s", p_gui->error->message );
g_free( p_gui->error );
return 1;
}
// Use Builder to connect gui objects to pointers and signals, then unreference
p_gui->window = GTK_WIDGET( gtk_builder_get_object( p_gui->builder, "window0" ) );
p_gui->img = GTK_WIDGET( gtk_builder_get_object( p_gui->builder, "img0" ) );
gtk_builder_connect_signals( p_gui->builder, p_gui );
g_object_unref( p_gui->builder );
//Show window
gtk_widget_show( p_gui->window );
return 0;
}
// Signal handler for Event Box button press event
void on_ebox0_button_press_event( GtkWidget * widget, GdkEvent * event, gpointer user_data )
{
s_data * sp_data = user_data;
// Assign event data (pointer coordinates on click) to data struct
sp_data->ptr_loc.x = event->button.x;
sp_data->ptr_loc.y = event->button.y;
sp_data->ctr_loc.x = WINDOW_CTR_X;
sp_data->ctr_loc.y = WINDOW_CTR_Y;
// Take it away, Ern!
takeItAway( sp_data );
}
// Signal handler for Event Box button release event
void on_ebox0_button_release_event( GtkWidget * widget, GdkEvent * event, s_data * sp_data )
{
// Possible future implementation
}
// Called when window is closed
void on_window0_destroy( )
{
gtk_main_quit( );
}
// Main
int main( int arg_num, char * arg_vec[] )
{
// Initialize GUI
s_gui * p_gui = g_slice_new( s_gui );
int pass = initGUI( p_gui, &arg_num, &arg_vec );
if( pass != 0 ){
printf( "Failed in initGui.\n" );
return -1;
}
// Begin GUI main
gtk_main( );
// Free GUI memory
g_slice_free( s_gui, p_gui );
return 0;
}
EDIT I forgot to include the glade file! (Thanks John):
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkWindow" id="window0">
<property name="name">window0</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="has-focus">True</property>
<property name="resizable">False</property>
<property name="default-width">440</property>
<property name="default-height">440</property>
<signal name="destroy" handler="on_window0_destroy" swapped="no"/>
<child>
<object class="GtkEventBox" id="ebox0">
<property name="name">ebox0</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<signal name="button-press-event" handler="on_ebox0_button_press_event" swapped="no"/>
<signal name="button-release-event" handler="on_ebox0_button_release_event" swapped="no"/>
<child>
<object class="GtkImage" id="img0">
<property name="name">img0</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can-focus">False</property>
<property name="pixbuf">gui_background.png</property>
<property name="icon_size">6</property>
</object>
</child>
</object>
</child>
</object>
</interface>
And here is the backtrace:
#0 0x00007ffff7289c11 in gdk_screen_get_default () at /lib/x86_64-linux-gnu/libgdk-3.so.0
#1 0x00007ffff7a4f5b3 in gtk_widget_get_display () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#2 0x00007ffff7a0b0fe in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#3 0x00007ffff7a49ca9 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#4 0x00007ffff7a4c17c in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#5 0x00007ffff7a4f3e4 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#6 0x00007ffff7a5d226 in gtk_widget_unparent () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#7 0x00007ffff77d7508 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#8 0x00007ffff76703ad in g_cclosure_marshal_VOID__OBJECTv ()
at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#9 0x00007ffff766d2ee in () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#10 0x00007ffff7685a48 in g_signal_emit_valist () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#11 0x00007ffff7685c3f in g_signal_emit () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#12 0x00007ffff78277a5 in gtk_container_remove () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#13 0x00007ffff7a540d4 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#14 0x00007ffff7673439 in g_object_run_dispose () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#15 0x00007ffff7a60829 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#16 0x00007ffff7829486 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#17 0x00007ffff766d0a2 in g_closure_invoke () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#18 0x00007ffff767f3ad in () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#19 0x00007ffff76856cf in g_signal_emit_valist () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#20 0x00007ffff7685c3f in g_signal_emit () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#21 0x00007ffff7a541b0 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#22 0x00007ffff7a67a78 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#23 0x00007ffff7673439 in g_object_run_dispose () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#24 0x00007ffff78ffa3d in gtk_main_do_event () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#25 0x00007ffff7a61737 in () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#26 0x00007ffff727fdd9 in () at /lib/x86_64-linux-gnu/libgdk-3.so.0
#27 0x00007ffff757bd6f in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#28 0x00007ffff757c118 in () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#29 0x00007ffff757c40b in g_main_loop_run () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#30 0x00007ffff78fea65 in gtk_main () at /lib/x86_64-linux-gnu/libgtk-3.so.0
#31 0x0000555555555912 in main (arg_num=1, arg_vec=0x7fffffffe098) at smallest_example.c:217
By commenting things out, I've found that in calcVectorInWheelSystem
, *trans_theta
, *trans_x
, and *trans_y
all cause a segfault, but I have the sneaking suspicion I've messed up something somewhere else.
Setting these to constants causes a series of GTK/GDK critical errors.
Setting these to the values of input variables (e.g., *theta
) causes a segfault in a different g_xxx
function.
Where am I going wrong?
Upvotes: 0
Views: 83