ET Come Back
ET Come Back

Reputation: 198

GTK+ C: Pointer Address Changing

I am getting a segmentation fault, due to a passed pointer's memory address changing when using GTK's g_signal_connect.

This is happening on only one of my three computers. The one computer where it is not working, it is running Arch Linux, so I am assuming that some program's version is ahead of my other computers which are both running Fedora. I assumed it was GTK+, so I tried downgrading, and this did not have any affect.

Weird thing... no matter where I compile the program, it always works on the two computers, and does not work on the one, so I don't believe it has anything to do with the compiler version.

Header File:

typedef struct Timer {
  gboolean running;
} *TimerP;

typedef struct TimerData {
  TimerP timerPointer;
} *TimerDataP;

Main:

TimerP timerPointer;
timerPointer = malloc(sizeof(struct Timer));

TimerDataP timerDataP;
timerDataP = malloc(sizeof(struct TimerData));
timerDataP->timerPointer = timerPointer;

g_signal_connect (startButton, "clicked", G_CALLBACK (startTimerPressed), timerDataP);

startTimerPressed function:

static void startTimerPressed (GtkWidget *widget, gpointer data, TimerDataP timerData) {
    TimerP timer = timerData->timerPointer;
}

To test, I have been doing this periodically, and this seems to work everywhere in main:

gpointer theGPointer;
startTimerPressed(startButton, theGPointer, timerDataP);

But for some reason, when it's called using the callback, the memory location has changed and all the data inside is messed up, so trying to access anything causes a segmentation fault.

Please & thank you for any assistance!

Complete Example:

#include <stdio.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <time.h>
#include <cairo.h>
#include <stdlib.h>

typedef struct Timer {
  gboolean running;
}*TimerP;

typedef struct TimerData {
  TimerP timerPointer;
} *TimerDataP;

static void startTimerPressed (GtkWidget *widget, gpointer data, TimerDataP timerData) {
  printf("TimerData Location: %p\n", timerData);
  TimerP timer = timerData->timerPointer;
}

int main (int argc, char *argv[]) {
  GtkWidget *startButton;
  GtkWidget *window;
  GtkWidget *grid;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_default_size(GTK_WINDOW(window), 550, 200);
  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
  gtk_container_set_border_width (GTK_CONTAINER (window), 20);

  grid = gtk_grid_new();
  gtk_grid_set_column_spacing(GTK_GRID(grid), 20);
  gtk_grid_set_row_spacing(GTK_GRID(grid), 10);
  gtk_container_add (GTK_CONTAINER (window), grid);

  startButton = gtk_button_new_with_label ("Start");

  TimerP timerPointer;
  timerPointer = malloc(sizeof(struct Timer));

  TimerDataP timerDataP;
  timerDataP = malloc(sizeof(struct TimerData));

  printf("TimerData Location: %p\n", timerDataP);

  g_signal_connect (startButton, "clicked", G_CALLBACK (startTimerPressed), timerDataP);
  gtk_grid_attach (GTK_GRID (grid), startButton, 0, 4, 1, 1);

  gtk_widget_show_all(window);

  gtk_main ();
}

On two of my computers, the memory location printed is the same in both locations, in one of them, it is different

Upvotes: 0

Views: 186

Answers (1)

andlabs
andlabs

Reputation: 11588

static void startTimerPressed (GtkWidget *widget, gpointer data, TimerDataP timerData) {

The gpointer data parameter is the data you pass to g_signal_connect(). You're asking for more parameters than the clicked signal gives you. It's a shame there's no way to check signal function parameters :/ You want

static void startTimerPressed (GtkWidget *widget, TimerDataP timerData) {

or

static void startTimerPressed (GtkWidget *widget, gpointer data) {
    TimeDataP timerData = (TimerDataP) data;

instead.

Upvotes: 1

Related Questions