The filename is a local variable and is not valid anymore after your function returns. The simple correction would be to make it static. Or, you define it somewhere else and pass the pointer to it as parameter by calling the function that opens the file. BTW, the function gtk_file_chooser_get_filename allocates a piece of memory for the returned string so you should free it after use, otherwise there is a memory leak.
I think I don’t understand your reply. (I generally write no C code )
My feeling is, that he does not try to return (the address) a local stack allocated variable, which would be invalid of course. He seems to try to return the value contained in filename variable, which is a pointer obtained from gtk_file_chooser_get_filename(). As you said yourself, gtk_file_chooser_get_filename() allocates that string, so it should exist after the function returns? Another remark, his usage of g_filename_to_utf8() seems to be wrong, as that function does not work in place, but returns a string. May that be related to his problem? I am really happy that I never had a teacher that gave me such types of homework.
@Agelos Better try to provide a minimal but complete code example. That would make it easier to find the issue.
Yes, you are absolutely right. The operation return filename; returns the pointer allocated by gtk_file_chooser_get_filename. And this pointer is valid even after the whole file open function has returned. The similar code (but without g_filename_to_utf8) works fine for me. The problem must be something else.
The filename is a local variable and is not valid anymore after your function returns.
But that’s the point; I don’t use it inside the function, I return it in another function. And considering the returned value is a heap pointer, why is the value destroyed after returning?
gtk_file_chooser_get_filename allocates a piece of memory for the returned string so you should free it after use, otherwise there is a memory leak.
I do that in the function that is calling this function.
A GTK bug seems to be unlikely. A C compiler issue may be possible, when you use a really strange compiler configuration. Computer programming is not writing some code and hoping that it works or that others fix the bugs for us. I have just spent more than four weeks fulltime (my summer holidays) to search for some obscure bugs in my tiny chess engine. For your file chooser, just create a tiny complete example like my GTK4 Nim example from GTK4 for Graphical User Interfaces and the issue will become obvious. It is really not that much work.
What I want to tell you is, that you should create a complete, compileable example like my one in your favorite language (C )and with your favorite GTK version
The function g_filename_to_utf8 does not seem to be the cause for the issue even if it is not properly used. If I see it right, the first parameter is not altered in any way.
Alright, here’s basically the example you asked for. Compiled with GCC, -fsanitize=address -Wall -Wextra $(pkg-config --cflags --libs gtk+-3.0) -O0 -ggdb3, tested on gdb for failure:
#include <gtk/gtk.h>
/* A macro to check if Gtk has been initialized. */
#define NVD_CHECK_GTK_INIT \
if (!gtk_init_check(NULL, NULL)) { \
return NULL; \
}
#ifndef NVDIALOG_MAXBUF
#define NVDIALOG_MAXBUF 4096
#endif /* NVDIALOG_MAXBUF */
/* THIS is the function that causes the problem. */
const char *nvd_open_file_dialog_gtk(const char *title,
const char *file_extensions) {
NVD_CHECK_GTK_INIT;
/* Creating the dialog. */
GtkWidget *dialog = gtk_file_chooser_dialog_new(
title, NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "Open",
GTK_RESPONSE_ACCEPT, "Cancel", GTK_RESPONSE_CANCEL, NULL);
/* Running the dialog and checking the user's action. */
int result = gtk_dialog_run(GTK_DIALOG(dialog));
if (result == GTK_RESPONSE_ACCEPT) {
GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
char *filename = gtk_file_chooser_get_filename(chooser);
/* For compatibility reasons, we need the filename in UTF-8
* format. */
g_filename_to_utf8(filename, strlen(filename), NULL, NULL,
NULL);
/* The dialog should be destroyed at this stage. */
gtk_widget_destroy(dialog);
/* Copying the value to the stack. */
char __buffer[NVDIALOG_MAXBUF];
/* Avoiding a warning. */
char *buffer = __buffer;
return buffer;
} else if (result == GTK_RESPONSE_CANCEL ||
result == GTK_RESPONSE_CLOSE) {
gtk_main_quit();
return NULL;
}
return NULL;
}
int main(int argc, char** argv)
{
gtk_init(&argc, &argv); /* In reality I only pass argv[0] because its a library */
const char* filename = nvd_open_file_dialog_gtk("Open file", NULL); /* We don't use the second parameter anyways. */
if (!filename) return -1;
puts(filename);
return 0;
}
This code for some reason won’t segfault but it returns 1. Without printing anything.
If you want the actual library code, I can give you the GitHub repo to test it yourself.
I am not really good at C. But with this tiny fix it works fine for me on Linux:
#include <gtk/gtk.h>
/* A macro to check if Gtk has been initialized. */
#define NVD_CHECK_GTK_INIT \
if (!gtk_init_check(NULL, NULL)) { \
return NULL; \
}
#ifndef NVDIALOG_MAXBUF
#define NVDIALOG_MAXBUF 4096
#endif /* NVDIALOG_MAXBUF */
/* THIS is the function that causes the problem. */
const char *nvd_open_file_dialog_gtk(const char *title,
const char *file_extensions) {
NVD_CHECK_GTK_INIT;
/* Creating the dialog. */
GtkWidget *dialog = gtk_file_chooser_dialog_new(
title, NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "Open",
GTK_RESPONSE_ACCEPT, "Cancel", GTK_RESPONSE_CANCEL, NULL);
/* Running the dialog and checking the user's action. */
int result = gtk_dialog_run(GTK_DIALOG(dialog));
if (result == GTK_RESPONSE_ACCEPT) {
GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
char *filename = gtk_file_chooser_get_filename(chooser);
/* For compatibility reasons, we need the filename in UTF-8
* format. */
/*g_filename_to_utf8(filename, strlen(filename), NULL, NULL,
NULL);*/
/* The dialog should be destroyed at this stage. */
gtk_widget_destroy(dialog);
/* Copying the value to the stack. */
char __buffer[NVDIALOG_MAXBUF];
/* Avoiding a warning. */
char *buffer = __buffer;
return filename;
} else if (result == GTK_RESPONSE_CANCEL ||
result == GTK_RESPONSE_CLOSE) {
gtk_main_quit();
return NULL;
}
return NULL;
}
int main(int argc, char** argv)
{
gtk_init(&argc, &argv); /* In reality I only pass argv[0] because its a library */
const char* filename = nvd_open_file_dialog_gtk("Open file", NULL); /* We don't use the second parameter anyways. */
if (!filename) return -1;
puts(filename);
return 0;
}
First run was your strange unfixed code. Actually I can not remember well how the old GTK3 file dialog worked – please check if the fixed code works for you.
#include <gtk/gtk.h>
/* A macro to check if Gtk has been initialized. */
#define NVD_CHECK_GTK_INIT \
if (!gtk_init_check(NULL, NULL)) { \
return NULL; \
}
#ifndef NVDIALOG_MAXBUF
#define NVDIALOG_MAXBUF 4096
#endif /* NVDIALOG_MAXBUF */
/* THIS is the function that causes the problem. */
const char *nvd_open_file_dialog_gtk(const char *title,
const char *file_extensions) {
NVD_CHECK_GTK_INIT;
/* Creating the dialog. */
GtkWidget *dialog = gtk_file_chooser_dialog_new(
title, NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "Open",
GTK_RESPONSE_ACCEPT, "Cancel", GTK_RESPONSE_CANCEL, NULL);
/* Running the dialog and checking the user's action. */
int result = gtk_dialog_run(GTK_DIALOG(dialog));
if (result == GTK_RESPONSE_ACCEPT) {
GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
char *filename = gtk_file_chooser_get_filename(chooser);
/* For compatibility reasons, we need the filename in UTF-8
* format. */
char *utfname = g_filename_to_utf8(filename, strlen(filename), NULL, NULL,
NULL);
/* The dialog should be destroyed at this stage. */
gtk_widget_destroy(dialog);
/* Copying the value to the stack. */
char __buffer[NVDIALOG_MAXBUF];
/* Avoiding a warning. */
char *buffer = __buffer;
return utfname;
} else if (result == GTK_RESPONSE_CANCEL ||
result == GTK_RESPONSE_CLOSE) {
gtk_main_quit();
return NULL;
}
return NULL;
}
int main(int argc, char** argv)
{
gtk_init(&argc, &argv); /* In reality I only pass argv[0] because its a library */
const char* filename = nvd_open_file_dialog_gtk("Open file", NULL); /* We don't use the second parameter anyways. */
if (!filename) return -1;
puts(filename);
return 0;
}
Of course later you have to care for freeing all the allocated strings. That is the result of coding in plain C.
If you insist on using C, then I recommend you read a book on the C programming language. “ANSI C, 2nd edition” is still a pretty solid book to learn the basics of the language, such as the difference between heap and stack allocations, and dealing with pointers.