gtkSourceView - usage of query-tooltip-text - c

I want to use the callback "query-tooltip-text" on my gtkSourceView. I connect the callback to the signal by using:
...
g_signal_connect(G_OBJECT(attributes), "query-tooltip-text", G_CALLBACK(on_lineMarkerTooltip_displayed), context->plainTextEditor_lineMarkers[lineNumber-1]->message);
This works fine .. whenever the tooltip should be displayed, my method is called. ...->message is a c-string which is in memory permanmently. Here my callback method:
gchar* on_lineMarkerTooltip_displayed(GtkSourceMarkAttributes *attributes, GtkSourceMark *mark, char* message)
{
printf("message3: %s\n", message); // just to see what is going on
return message;
}
The gtk3 source doc stats that I should control the lifetime of the string and free it when done, I think that should be fine.
However my callback fails with a double-free segfault after it is called the second time:
...
message3: bad hour
message3:
message3: `�/EV
*** Error in `./cron-gui': double free or corruption (fasttop): 0x000056452fc70240 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x70bcb)[0x7f85670a9bcb]
/lib/x86_64-linux-gnu/libc.so.6(+0x76f96)[0x7f85670aff96]
/lib/x86_64-linux-gnu/libc.so.6(+0x7778e)[0x7f85670b078e]
/usr/lib/x86_64-linux-gnu/libgtk-3.so.0(+0x214447)[0x7f85694
...
So different than told in the official doc, it looks like gtk3 frees the memory of the string after usage. I tried to modify my callback accordingly like that:
gchar* on_lineMarkerTooltip_displayed(GtkSourceMarkAttributes *attributes, GtkSourceMark *mark, char* message)
{
printf("message3: %s\n", message); // just to see what is going on
return strdup(message);
}
Which works well, however I fear that my application could eat memory now.
Do you know what is the correct usage of the query-tooltip-text callback ?

Ok, I checked the source-code of libgtksourceview: The string is freed by the library, the documenation for the signal-handler is just wrong.
I filed a bug for the maintainers of the package here:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=857873
So actually it is correct to use
...
return strdup(message);
...

Related

ctypes callback function throws SIGSEGV

I got a c library, that needs some callbacks,
they are handled in a linked list.
the python callable are those:
def callback_exit():
print("exiting.")
sys.exit(0)
# never reached
return c_int(0)
def hw_print_int():
print("foo")
return c_int(0)
I add them to the list like this:
SFR_COMM=CFUNCTYPE(c_voidp)
class MyClass:
def add_SFR_callback(self,operation_number,callback):
all_callbacks=c_voidp.in_dll(self.memlib,"sfr_comms")
my_callback=self.memlib.newSFRCommand(c_uint(operation_number),callback)
new_all_callbacks=self.memlib.new_SFRCommandHolder(my_callback,all_callbacks)
self.memlib.set_sfr_comms(new_all_callbacks)
my_class_object.add_SFR_callback(0xff,SFR_COMM(callback_exit))
my_class_object.add_SFR_callback(0xff,SFR_COMM(hw_print_int))
this works fine, until the callback is called, then I receive just a SIGSEGV.
Important: the SIGSEGV tells me, that it is an "Ungültiger Maschinenbefehl" (Translation: invalid processor directive or something like that)
So I just do not know how I can fix it.
This is the c code:
struct _SFRCommandHolder * sfr_comms;
#define DEBUG
unsigned int SpecialFunctionRegister_exec(unsigned int val)
{
struct _SFRCommandHolder * curr=sfr_comms;
unsigned int ret=-1;
while (curr!=NULL)
{
#ifdef DEBUG
printf("( %zd => %zd => %zd ) %u ?= %u",curr,curr->com,curr->com->funct,curr->com->val,val);
#endif
if(curr->com->val==val)
{
#ifdef DEBUG
printf("\t\tTRUE\n");
#endif
ret=curr->com->funct(); // <= SIGSEGV here
#ifdef DEBUG
printf("callback done.\n");
#endif
}
#ifdef DEBUG
else
{
printf("\t\tFALSE\n");
}
#endif
curr=curr->next;
}
return ret;
}
I do not think, that sys.exit is a problem, as it worked a few commits before just fine.
Edit:
calling hw_print_int works just fine, but callback_exit does not work.
btw: if I do not add hw_print_int, callback_exit works, too
output:
( 13185760 => 13136448 => 139994994819144 ) 3 ?= 255 FALSE
( 13038864 => 13034576 => 139994994819088 ) 255 ?= 255 TRUE
Ungültiger Maschinenbefehl (Speicherabzug geschrieben)
In here, you have pointers to struct _SFRCommandHolder but where does the data live? Where did you allocated a struct _SFRCommandHolder?
If the response is "nowhere", your code has undefined behaviour as sfr_comms may have any value (and especially non NULL value); this result in curr->com causing segmentation fault almost everytime.
The problem is, that the python garbage collection removes
objects without (strong) reference to them.
From https://docs.python.org/3/library/ctypes.html#callback-functions
Note
Make sure you keep references to CFUNCTYPE() objects as long as they are used from C code. ctypes doesn’t, and if you don’t, they may be garbage collected, crashing your program when a callback is made.
Also, note that if the callback function is called in a thread created outside of Python’s control (e.g. by the foreign code that calls the callback), ctypes creates a new dummy Python thread on every invocation. This behavior is correct for most purposes, but it means that values stored with threading.local will not survive across different callbacks, even when those calls are made from the same C thread.
It seems like it is not enough to reference to them using the struct _SFRCommandHolder *.
So adding another reference is enough:
class MyClass:
def __init__(self,*args):
# ...
self.refs=[]
def add_SFR_callback(self,operation_number,callback):
all_callbacks=c_voidp.in_dll(self.memlib,"sfr_comms")
my_callback=self.memlib.newSFRCommand(c_uint(operation_number),callback)
new_all_callbacks=self.memlib.new_SFRCommandHolder(my_callback,all_callbacks)
self.memlib.set_sfr_comms(new_all_callbacks)
self.refs.append(callback)

Can't free() a char*

void* password_cracker_thread(void* args) {
cracker_args* arg_struct = (cracker_args*) args;
md5hash* new_hash = malloc (sizeof(md5hash));
while(1)
{
char* password = fetch(arg_struct->in);
if(password == NULL )
{
deposit(arg_struct->out,NULL);
free(new_hash);
pthread_exit(NULL);
}
compute_hash(password,new_hash);
if(compare_hashes(new_hash,(md5hash**)arg_struct->hashes,arg_struct->num_hashes) != -1)
{
printf("VALID_PASS:%s \n",password);
deposit(arg_struct->out,password);
}else{
free(password);
}
}
}
This is a part of a program, where you get char* passwords from a ringbuffer, calculate md5 and compare them and push them into the next buffer if valid.
My problem is now, why can't I free those I don't need?
The whole program will stop if I try to and if I don't, I get memory leaks.
"You", and by this I mean your program, can only free() storage that was got from malloc()-and-friends, and only in the granularity it was got, and only once per chunk of storage.
In the code you show here, you're attempting to free() something got from fetch(). Since we can't see the definition of that function and you have not provided any documentation of it, our best guess is that
fetch() gives you a pointer to something other than a whole chunk
got from malloc()-et-al; and/or
some other part of the program not
shown here free()s the relevant chunk itself.

Memory leaks from splitting and duplicating strings

I am working on a fairly simple application written in C with GTK+ that is leaking memory badly. It has a few basic functions on timers that check the clock and poll an external networked device, parsing the string returned. The application runs on a small touch panel, and through TOP I can watch the available memory be eaten up as it runs.
I'm pretty new to C, so not surprised that I'm doing something wrong, I just can't seem to figure out what. I've been trying to use Valgrind to narrow it down, but honestly the output is a little over my head (10k+ line log file generated from running the application less than a minute). But in digging through that log I did find some functions repeatedly showing up with permanently lost blocks, all using some similar structure.
Example 1:
This is a short function that gets called when an option is selected. The last line with the g_strdup_printf is the one called out by Valgrind. select_next_show and select_show_five_displayed are both global variables.
static void show_box_five_clicked ()
{
g_timer_start(lock_timer);
gtk_image_set_from_file (GTK_IMAGE(select_show_1_cb_image), "./images/checkbox_clear.png");
gtk_image_set_from_file (GTK_IMAGE(select_show_2_cb_image), "./images/checkbox_clear.png");
gtk_image_set_from_file (GTK_IMAGE(select_show_3_cb_image), "./images/checkbox_clear.png");
gtk_image_set_from_file (GTK_IMAGE(select_show_4_cb_image), "./images/checkbox_clear.png");
gtk_image_set_from_file (GTK_IMAGE(select_show_5_cb_image), "./images/checkbox_checked.png");
select_next_show = g_strdup_printf("%i",select_show_five_displayed);
}
Example 2:
This is another function that gets called often and came up a lot in the Valgrind log. It takes the incoming response from the networked device, parses it into two strings, then returns one.
static gchar* parse_incoming_value(gchar* incoming_message)
{
gchar *ret;
GString *incoming = g_string_new(incoming_message);
gchar **messagePieces = g_strsplit((char *)incoming->str, "=", 2);
ret = g_strdup(messagePieces[1]);
g_strfreev(messagePieces);
g_string_free(incoming, TRUE);
return ret;
}
In all the cases like these which are causing problems I'm freeing everything I can without causing segmentation faults, but I must be missing something else or doing something wrong.
UPDATE:
To answer questions in comments, here is an example (trimmed down) of how I'm using the parse function and where the return is freed:
static void load_schedule ()
{
...other code...
gchar *holder;
gchar *holder2;
holder = read_a_line(schedListenSocket);
holder2 = parse_incoming_value(holder);
schedule_info->regShowNumber = holder2;
holder = read_a_line(schedListenSocket);
holder2 = parse_incoming_value(holder);
schedule_info->holidayShowNumber = holder2;
...other code....
g_free(holder);
g_free(holder2);
}
Any help is greatly appreciated!!
It looks like you free 'ret' once when calling g_free(holder2), but you've done multiple allocations for that one free - you call parse_incoming_value multiple times, each time causing an allocation, but you only free once right at the end.
As you copy the holder2 pointer into schedule_info elements each time, they actually have the "leaked" memory at the end.
If you do not free holder2 anywhere, but just free all the elements in schedule_info at the end of the code. I presume that shows no leak?
e.g.
holder2 = <result of dynamic alloc>;
schedule_info->a = holder2;
...
holder2 = <result of dynamic alloc>;
schedule_info->b = holder2;
...
// instead of g_free(holder2) at the end, do this...
g_free(schedule_info->a);
g_free(schedule_info->a);

Invalid free() / delete / delete[] / realloc() with g_string_free()

I have a GList which contains a collection of GSList. This GSlist contains a collection of GString. When I free the whole GList, I get segmentation fault.
Now check the following code.
GList *m_rows = NULL;
m_rows = mysql_multiple_rows(mysql, sql1->str);
g_list_foreach(m_rows, mysql_storage_load_settings, &data);
mysql_free_multiple_rows(m_rows); /// <----------------------- works just fine
m_rows = mysql_multiple_rows(mysql, sql2->str);
if(g_list_length(m_rows)>0){
g_list_foreach(m_rows, mysql_storage_load_accounts, &data);
mysql_free_multiple_rows(m_rows); /// <----------------------- Segmentation fault!
}else{
fprintf(stderr, "\e[31m\tUser has no account!\e[0m");
}
So m_rows are only allocated using g_string_new(), g_slist_prepend() and g_list_prepend(). g_string_new() creates new GString and added to a GSList. all the resultant GSList then get added to GList. It happens in mysql_multiple_rows function.
They are free'd using mysql_free_multiple_rows. This function just does the reverse.
See the clean up functions.
static void mysql_free_multiple_rows(GList *table){
g_list_free_full(table, mysql_free_single_row);
}
static void mysql_free_single_row(gpointer data){
g_slist_free_full(data, msyql_free_single_row_field); // data here is GSlist
}
static void msyql_free_single_row_field(gpointer data){
g_string_free(data, TRUE); // data here is GString actually
}
Could anyone tell me why I am getting this error? As both the memory allocation and de-allocation sequence are same I have no clue why its happening.
Valgrind output
Source file
Looking at the code, you seem to be freeing password in mysql_storage_load_accounts(). However, I don't see any special handling for it, so my guess would be that it gets freed twice.

[C]Dynamic allocation memory of structure, related to GTK

I have following structure:
typedef struct
{
GtkWidget* PoziomaLinijka;
GtkWidget* PionowaLinijka;
GtkWidget* Label1;
GtkWidget* Label2;
gint x,y;
} StrukturaDrawing;
And i need to allocate it on the heap because later I have functions which uses that structure and I don't want to use global variables. So I allocate it like this:
StrukturaDrawing* Wsk;
Wsk = (StrukturaDrawing*)malloc(sizeof(StrukturaDrawing));
if (!Wsk)
{
printf("Error\n");
}
And it doesn't returning error and also works great with other functions, it works the way I wanted it to work so finally i wanted to free that memory and here is problem because in Debug Mode compilator bitches:
First-chance exception at 0x102d12b4 in GTK.exe: 0xC0000005: Access violation reading location 0xfffffffc.
Unhandled exception at 0x102d12b4 in GTK.exe: 0xC0000005: Access violation reading location 0xfffffffc.
I connect callback to my function, like that:
g_signal_connect(G_OBJECT(Okno), "destroy", G_CALLBACK(Wyjscie), Wsk);
Function which is suppose to free memory and close program:
void Wyjscie(GtkWindow* window, GdkEvent* event, StrukturaDrawing* data)
{
gtk_main_quit();
free(data);
data = NULL;
}
Any help really appreciated.
Well durning debugging data structure have following values:
The first one has: PoziomaLinijka CXX0017: Error: symbol "" not found
And later the whole rest have: PionowaLinijka CXX0030: Error: expression cannot be evaluated
Oh: I am the oen who started question, sorry about confusing with nicknames.
The "destroy" signal has a different signature for its callback than your Wyjscie function. Maybe you rather want the "destroy-event" of GtkWidget, see docshere
If you want the "destroy" event of GtkObject, see here, you have to change your callback to
void Wyjscie(GtkObject* window,StrukturaDrawing* data)
{
gtk_main_quit();
free(data);
}

Resources