sqlite3 library undefined reference error - c

I am creating a word list searcher in C for my program using sqlite3 but I've got these errors .
I tried whatever I knew but it didn't fixed. I guess the problem is in my join function but I am not sure.
code :
bool *gb_wordlist_add_to_list (gbwordlist *word_list,char *str)
{
int sql_error;
char *error_massage;
if (gb_wordlist_in_list (word_list,str))
{
sql_error = sqlite3_execute(word_list->database, gb_wordlist_join(ADD_TO_TABLE_COMMAND"\'",str,"\';"),
NULL ,NULL, &error_massage);
if( sql_error!=SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", error_massage);
sqlite3_free(error_massage);
return 0;
}
}
else
return 0;
}
char *gb_wordlist_join (char *s1,char *s2,char *s3){
char *s;
s = malloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
if(s)
{
strcpy(s,s1);
strcat(s,s2);
strcat(s,s3);
}
return s;
}
error:
gb-sql.o: In function `gb_wordlist_remove_from_list':
/home/reza/Project/GB/Search algorithm/Source/gb-search/src/gb-sql.c:104: undefined reference to `sqlite3_execute'
Also my full codes are here. Thanks a lot!

The reason you are getting undefined reference to sqlite3_execute is well there is no such function as part of library. You probably meant to use sqlite3_exec (which use have used in some parts of the code).
Side Notes:
The function gb_wordlist_callback is returning int but has been declared to return int*. You should change the return type to int to match the expected parameters to be passed to sqlite3_exec(after modifying from sqlite3_execute)
The 4th parameter passed to sqlite3_exec (after modifying from sqlite3_execute) is expected to be void* so existance should be &existance
You have quite a few functions with mismatch between return type declared and the actual return type returned from the function.
Compile your code with -Wall -Wextra compiler options & fix all the warnings. It is good practice.
Hope this helps!

Related

Is there an attribute to tell the compiler to ignore a missing return statement?

I don't believe this is a duplicate because the function does return in the happy path. Using the attribute no-return allows the compiler to optimise on the assumption that the function never returns, which is not the case here.
I have come C code that either returns a pointer or calls another function to exit out of the program. This is in an if statement, so either it returns the result or exits. As the function returns a void *, the compiler warns that it's possible the function won't return a value (which is of course true):
error: control reaches end of non-void function [-Werror=return-type]
I can get around this by just adding return *temp; to the end of the function but I'd like to be clear in my intent by having something like the unused variable attribute:
__attribute__((__unused__))
That way I can leave -Wall on and not have to add unnecessary or possibly confusing code.
I'd also be up for rewriting the code if there's a better way to express this intent.
The code looks something like:
void *get_memory() {
void *temp = malloc(100);
if (temp) {
// do some setup work
return temp;
} else {
exit_program_with_epic_fail();
}
// Compiler warns if the following line isn't present
return temp;
}
There are 2 ways to get rid of the warning:
tag the exit_program_with_epic_fail() function with the appropriate attribute, _Noreturn in C11, but there is no portable way to do this to pre-C11 compilers. Many compilers support __attribute__((noreturn)), notably gcc, clang and tinycc, but it is an compiler specific extension.
reorganise the code to let the compiler see the function always return.
Here is a modified version:
void *get_memory(void) {
void *temp = malloc(100);
if (!temp) {
exit_program_with_epic_fail();
}
// do some setup work
return temp;
}
This seems to be a pure design problem.
The warning/error "control reaches end of non-void function" isn't the problem, it is rather just an indicator telling you where the actual problem is.
You could/should simply rewrite the function as
void *get_memory (void)
{
void *temp = malloc(100);
if(temp != NULL)
{
// do stuff
}
return temp;
}
And leave error handling to the caller. Because it is not an allocation function's job to terminate the application - that's bad design.
Alternative version with detailed error handling:
typedef enum
{
OK,
ERR_OUTOFMEMORY,
...
} err_t;
err_t get_memory (void** mem)
{
*mem = malloc(100);
if(*mem == NULL)
{
return ERR_OUTOFMEMORY;
}
// do stuff
return OK;
}

Error caused by function that hasn't yet been run

So I'm writing a bill handling system. The data currently sits in a Stack structure that I've written.
I have this partially written function that writes out a report:
void GenerateReport(Bill* bill)
{
PrintBillHeading(bill);
//CallEntry* collatedEntries = CollapseCallStack(bill->callEntries);
//TODO
}
Which works fine as long as I leave the second line commented out. If I uncomment it I get a SIGSEGV fault within the PrintBillHeading() function where indicated below.
void PrintBillHeading(Bill* bill)
{
printf("Big Brother Telecom\n");
printf("Bill Date: %s\n\n",DateTimeToISOString(bill->date));
printf("Contract Holder: %s %s\n", bill->title, bill->name);
printf("Address:\n");
char* addressSeg;
char* addressCpy;
strcpy(addressCpy,bill->address); //This line throws the SIGSEGV
while ((addressSeg = strtok_r(addressCpy,";",&addressCpy)))
{
printf("%s\n\0",addressSeg);
}
}
and for completeness here is my CollapseCallStack() function, this is uncomplete, entirely untested and probably doesn't work.
CallEntry* CollapseCallStack(Stack* calls)
{
int size = calls->topIndex;
CallEntry* collatedSet = malloc(sizeof(CallEntry) * size);
CallEntry* poppedCall;
int curIndex = 0;
while (PopStack(calls,poppedCall))
{
bool found = false;
for (int i = 0; i < size; i++)
{
CallEntry* arrItem = collatedSet + i * sizeof(CallEntry);
if (StringEquals(arrItem->phoneNumber,poppedCall->phoneNumber))
{
found = true;
arrItem->minutes += poppedCall->minutes;
}
}
if (!found)
{
memcpy(collatedSet,poppedCall,sizeof(CallEntry)); //
}
}
}
And the CallEntry struct:
typedef struct{
char* phoneNumber;
int minutes;
DateTime* callDateTime;
} CallEntry;
My question is this: how can a function that hasn't yet been called cause a SIGSEGV fault to be expressed earlier on in a program?
Once I've got past this, I can debug the CollapseCallStack() function myself, although if anyone sees any glaring problems I would appreciate a comment on that.
In function PrintBillHeading(), the statement strcpy(addressCpy,bill->address) uses the value of an uninitialized variable addressCpy. This is undefined behavior. Undefined behavior means that the program may crash in any random place. If the program contains undefined behavior the entire program is invalid.
In addition to the correct answer by AlexP, I'd like to point out another (lurking) undefined behaviour:
void GenerateReport(Bill* bill)
{
PrintBillHeading(bill);
CallEntry* collatedEntries = CollapseCallStack(bill->callEntries);
//TODO
}
Now, CollapseCallStack in your current implementation does not return anything. It will still be called, and actually something will be assigned to your collatedEntries pointer upon your initialization of it.
The problem is that when CollapseCallStack is called, memory for the return value is being allocated, but it never gets assigned a meaningful value, since the return statement is missing. So, essentially your collatedEntries pointer will be initialized with a random garbage value, and if you'd try to dereference it, it would cause UB.

Warning 'return' with no value, in function returning non-void - What should it return?

How do I solve the following throwing the warning in the title?
struct Nodes* InsertNode(unsigned int IP, unsigned short Port)
{
if (!IP)
return;
if (!Port)
return;
// Above is what chucks the warnings
{
// do stuff & conditionally
return &List[x];
}
// Different conditions & stuff
{
return &List[Other];
}
}
In other words, in the case of giving up through missing data, what should it return? Or do I need to trawl through the entire body of code and have checks every time to see if it should be called or not? The program functions as intended just returning at that point, if I'm to continue using it (or upgrade the OS it's running on), fixing compiler warnings seems like a good idea, they tend to turn into errors when compiler versions get bumped.
There's a clue in this answer which answers someone asking about the same warning, the answer doesn't give me quite enough info to proceed though, nor do the other's I've read.
Extra information: The check on the values of IP & Port are there to sanitize the content of &List, such cases indicate datagrams from misconfigured clients or traffic from persons with malicious intent, sad but it happens. It's invalid data we don't care about at all, logging it seems pointless, it shouldn't delay processing the next one, and absolutely not halt the program. Until the switch from gcc 4.9 to 6.3 I didn't see a warning. The current return; appears to simply black-hole it, but I only understand bits of the code's intent.
in the case of giving up through missing data, what should it return?
As often it depends.
There are several scenarios
The function is not designed to return NULL as a valid value.
Replace
if (!IP)
return;
if (!Port)
return;
by
if (!IP || !Port)
{
errno = EINVAL; /* Setting errno, allows the caller to log
the failure using the perror() function. */
return NULL;
}
Use it like this:
struct Nodes * p = InsertNode (...);
if (NULL == p)
{
perror("InsertNode() failed");
/* exit or error logging/handling */
}
IP and Port will never be 0 under normal operation. So if they were it would be a programming mistake.
In those cases you probably no don't return but end the program.
So instead of
if (!IP)
return;
if (!Port)
return;
use
assert((IP) && (Port));
No specific usage necessary here as the program would simply end if the assertion isn't met.
Please note that this approach requires extensive testing as the test will typically be removed in a production/release build!
The function may return NULL as valid value and IP and/or Port may be 0 under normal operation.
Redesign the function to in one way or the other return a separate error status.
This can generally be done in two ways:
Use the function's return value and pass back the result via a pointer being passed as parameter
int InsertNode(unsigned int IP, unsigned short Port, struct Nodes** ppresult)
{
int error_state = 0;
if (!IP || !Port || !ppresult)
{
errno = EINVAL; /* Setting errno, allows the caller to log
the failure using the perror() function. */
error_state = -1;
}
else
{
if (...)
{
*ppresult = &List[x];
}
...
}
return error_state;
}
Use it like this:
struct Nodes * p;
if (-1 == InsertNode (..., &p))
{
perror("InsertNode() failed");
/* exit or error logging/handling */
}
Pass back the error state result via a pointer being passed as parameter
struct Nodes * InsertNode(unsigned int IP, unsigned short Port, int * perror_state)
{
int error_state = 0;
if (!IP || !Port || !perror_state)
{
errno = EINVAL; /* Setting errno, allows the caller to log
the failure using the perror() function. */
error_state = -1;
}
else
{
if (...)
{
*ppresult = &List[x];
}
...
}
*perror_state = error_state;
return NULL;
}
Use it like this:
int result;
struct Nodes * p = InsertNode (..., &result))
if (-1 == result)
{
perror("InsertNode() failed");
/* exit or error logging/handling */
}
TLDR
"Until the switch from gcc 4.9 to 6.3 I didn't see a warning." Try compiling with gcc -std=gnu90 to compile under similar conditions to those that worked before, when you were using gcc 4.9.
OK, I'm Listening
The reason that you see compiler warnings after changing compilers from gcc 4.9 to gcc 6.3 is that gcc 4.9 defaulted to C90 (really the gnu90 dialect of C90), but by gcc 5.5 the default was C11 (really gnu11).
The C90 Standard says in the Constraints section about the return statement that (C90 §6.6.6.4):
A return statement with an expression shall not appear in a function whose return type is void.
But the same Constraints section from the C11 Standard saysC11 §6.8.6.4:
A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.
Now, the compiler must produce a diagnostic message for any constraint violation (§5.1.1.3). No constraint was violated when your code was compiled under C90, but the change to a more recent compiler means that the code now compiles under C11, where there is a constraint violation, hence the warning.
One option would be to simply compile with gcc -std=gnu90, allowing the code to be compiled using the same dialect of C you used before, even on the more recent compilers.
But, also note that the original code may have had undefined behavior, since (C90 §6.6.6.4):
If a return statement with an expression is executed, and the value of the function call is used by the caller, the behavior is undefined.
If the value returned by InsertNode() is used by the caller, and the return; statement is encountered in the function call, you have undefined behavior. The best choice would be to look at all of the calls to InsertNode() to see how they handle the return values. It is possible that return; is a typo, and that the code already handles returned null pointers, in which case changing to return NULL; would be all that is needed to fix the code. If the code does not already handle null pointers, #alk has provided several options for fixing the code.

Warnings with pointer using .cfg file

I try to setup a c programm using the libconfig. There is example1.c:
int main()
{
const char **channel;
config_t config;
config_init(&config);
config_read_file(&config, "example.cfg");
if( config_lookup_string(&config,"value.channel",&channel) == CONFIG_FALSE)
{
printf("Failed to read fields\n");
return 1;
}
printf("argumente = %s\n", (char *)channel);
return 0;
}
and the example.cfg file
value = { channel = "hello"; }
if I compile it
gcc example1.c -lconfig
it says:
example1.c:39:3: Warning: delivery of arguments 3 from »config_lookup_string« of a incompatible pointer
/usr/include/libconfig.h:244:26: Detailed: »const char **« expected, but argument has typ »const char ***«
The funny thing is it works... the output is:
argumente = hello
How can I get rid of this warning ?
If I change the decleration to const char *channel and the output printf("argumente = %s\n", channel);, I receive a segfault at start and a warning at compiling like ... Detailed: »const char **« expected, but argument has typ »const char *«
You just need to get rid of one * in your declaration of channel. If you do that, you can also remove the cast in your printf call.
The reason it's "working" now is that cast is hiding a second warning about your printf format. Your program is behaving just like the extra * was removed already - just in a confusing way.

C definition of: static void (*var_name)();

I download a code example written in C, but don't understand one instruction. And besides, w
hen i try to compile the code the compiler throws me an error just in the line that i don't understand.
Code:
// Global vars
static int getting_text = 0;
static char *the_text; // Definition Part
static void (*text_entered)(); // Definition Part 2
// method
int add_text(unsigned char key)
{
char msg[] = "x";
int len;
if(!getting_text) return 0;
if(key==8) /* backspace */
{
len = strlen(the_text);
the_text[len-1] = '\0';
}
else if(key==13 || key==9) // cr or tab ends
{
getting_text = 0;
text_entered(the_text); // Execution Part
}
else
{
msg[0] = key;
strcat(the_text, msg);
}
glutPostRedisplay();
return 1;
}
The compiler throws me an error about there are too many arguments in the method's calling. But i don't if it's a method the static void (*xxx)() or if other thing.
Thanks in advance.
EDIT: The following only applies to C++. Did you use g++ or some other C++ compiler instead of a C compiler?
text_entered is a function pointer to a function that doesn't take any arguments, hence the error, because you're passing it a character pointer. I assume it should change to,
static void (*text_entered)(char*);
This is of course assuming text_enterered actually gets set to a function that takes a char* argument and it isn't just being called wrong.

Resources