manateed
manateed

Reputation: 1

c - segfault in gdk function if assigning value to (subsequent) struct variables

Description

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

Attempts

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

Answers (0)

Related Questions