GDB cannot tell different source files when compiling them within #include? - c

Just a small program of stdarg.h, when I organizing source file in a single source file as following:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void
print(const char *, ...);
void
print(const char *format, ...)
{
va_list vlist;
va_start(vlist, format);
vfprintf(stdout, format, vlist);
va_end(vlist);
return;
}
int
main(int argc, char **argv)
{
const char *message = "Just a test";
print("==> %s <==\n", message);
return EXIT_SUCCESS;
}
The below code in a single file works well under gdb when debugging, it stopped where I expected.
But when I organizing the code in 3 files: print.c main.c test.c
/* print.c */
void
print(const char *, ...);
void
print(const char *format, ...)
{
va_list vlist;
va_start(vlist, format);
vfprintf(stdout, format, vlist);
va_end(vlist);
return;
}
/* main.c */
int
main(int argc, char **argv)
{
const char *message = "Just a test";
print("==> %s <==\n", message);
return EXIT_SUCCESS;
}
/* test.c */
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include "print.c"
#include "main.c"
I use command gcc -g test.c, and run it under linux. When breaking at print, it refused to break and continue to run to the end, within a warning "error removing breakpoint 0".
I suppose that maybe it related to stdarg.h, because I am always organizing code in that way, but the first time met the problem.

Related

Can I know the file and function names from where my function is called if it's from another .c?

I'm developing a library and I would like to know some data about the caller of one of the functions I'm offering. In particular, I would need to know the file name, function name and line where my function (a redefined malloc) is being called.
EDIT: Here's a minimum working example where I can detect when a user calls malloc and "redirect" him to my own malloc function:
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "myLib.h"
int main(){
printf("Inside main, asking for memory\n");
int *p = malloc(sizeof(int));
*p = 3;
free(p);
return 0;
}
myLib.c:
#include "myLib.h"
void * myAlloc (size_t size){
void * p = NULL;
fprintf(stderr, "Inside my own malloc\n");
p = (malloc)(size);
return p;
}
#undef malloc
#define malloc(size) myAlloc(size)
myLib.h:
#ifndef MYLIB_H
#define MYLIB_H
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define malloc(size) myAlloc(size)
void * myAlloc(size_t size);
#endif
I've tried using _FILE_ _func_ and _LINE_ keywords, but I can't make it work since it's in a different module.
You could:
//mylib.h
#ifndef MYLIB_H
#define MYLIB_H
#include <stdlib.h>
// replace malloc in case it's already a macro
#ifdef malloc
#undef malloc
#endif
// I believe that from the standards point of view, this is undefined behavior
#define malloc(size) my_alloc(size, __FILE__, __LINE__, __func__)
#ifdef __GNUC__
// Allow compiler to do static checking.
__attribute__((__alloc_size__(1), __malloc__))
#endif
void *my_alloc(size_t size, const char *file, int line, const char *func);
// ^^^^^^^^ I do not like camelCase case - one snake case to rule them all.
#endif
// mylib.c
#include "mylib.h" // do not ever mix uppercase and lowercase in filenames
#undef malloc // undef malloc so we don't call ourselves recursively
#include <stdio.h>
void *my_alloc(size_t size, const char *file, int line, const char *func){
fprintf(stderr, "Och my god, you wouldn't believe it!\n"
"A function %s in file %s at line %d called malloc!\n",
func, file, line);
return malloc(size);
}
You might also see how assert does it. If you are aiming at glibc, read glibc docs replacing malloc.
Still as you discovered a user may do (malloc)(size) cicumvent macro expansion. You could do:
void *my_alloc(size_t size, const char *file, int line, const char *func);
static inline void *MY_ALLOC(size_t size) {
return my_alloc(size, NULL, 0, NULL);
}
#define MY_ALLOC(size) my_alloc(size, __FILE__, __LINE__, __func__)
// if called with `malloc()` then MY_ALLOC is expanded
// if called as `(malloc)`, then just expands to MY_ALLOC.
#define malloc MY_ALLOC
int main() {
malloc(10); // calls my_alloc(10, "main.c", 62, "main");
(malloc)(20); // calls my_alloc(20, NULL, 0, NULL);
}
GLIBC defines hidden symbols for malloc(), free()... which are called __libc_malloc(), __libc_free()...
So, you can tremendously simplify your debug macros.
In m.h, just define the following:
#if DEBUG_LEVEL > 0
extern void *__libc_malloc (size_t bytes);
extern void *myMalloc(size_t size, const char *filename, const char *funcname, int line);
#define malloc(size) myMalloc(size, __FILE__, __FUNCTION__, __LINE__)
#endif
Then you can write a program defining myMalloc() as follow (e.g. file name is m.c):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "m.h"
#if DEBUG_LEVEL > 0
void *myMalloc(
size_t size,
const char *filename,
const char *funcname,
int line
) {
fprintf(stderr, "malloc(%zu) called from %s/%s()#%d\n", size, filename, funcname, line);
return __libc_malloc(size);
}
#endif
char *dup_str(char *string) {
char *str = malloc(strlen(string) + 1);
strcpy(str, string);
return str;
}
int main(int ac, char *av[]) {
char *str;
if (av[1]) {
str = dup_str(av[1]);
} else {
str = dup_str("NULL");
}
printf("String = '%s'\n", str);
free(str);
return 0;
}
When you compile this example program in non debug mode:
$ gcc m.c -DDEBUG_LEVEL=0
$ ./a.out azerty
String = 'azerty'
When you compile your program in debug mode:
$ gcc m.c -DDEBUG_LEVEL=1
$ ./a.out azerty
malloc(7) called from m.c/dup_str()#27
String = 'azerty'

Why using crypt in glibc cause compiler warning?

I tried to compiler the following code(minimum example, see the edit for the whole code):
// a.c
#include <stdio.h>
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "$6$2222"));
return 0;
}
Using clang-7 -lcrypt a.c and it emitted the following warning:
minimum.c:8:24: warning: implicit declaration of function 'crypt' is invalid in C99 [-Wimplicit-function-declaration]
puts((const char*) crypt("AAAA", "$6$2222"));
^
minimum.c:8:10: warning: cast to 'const char *' from smaller integer type 'int' [-Wint-to-pointer-cast]
puts((const char*) crypt("AAAA", "$6$2222"));
^
2 warnings generated.
But ./a.out did seem to work:
$6$2222$6GKY4KPtBqD9jAhwxIZGDqEShaBaw.pkyJxjvSlKmtygDXKQ2Q62CPY98MPIZbz2h6iMCgLTVEYplzp.naYLz1
I found out that if I remove #include <stdio.h> and puts like this:
// new_a.c
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
crypt("AAAA", "$6$2222");
return 0;
}
Then there is no warnings.
How to fix these warnings without removing #include <stdio.h>?
Edit:
Whole program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _X_OPEN_SOURCE
#include <unistd.h>
#include <assert.h>
void* Calloc(size_t cnt, size_t size)
{
void *ret = calloc(cnt, size);
assert(ret);
return ret;
}
size_t GetSaltLen(const char *salt)
{
size_t salt_len = strlen(salt);
assert(salt_len > 0);
assert(salt_len <= 16);
return salt_len;
}
char* GetSaltAndVersion(const char version, const char *salt)
{
size_t saltlen = GetSaltLen(salt);
/*
* The format of salt:
* $one_digit_number$up_to_16_character\0
* For more info, check man crypt.
*/
char *ret = (char*) Calloc(1 + 1 + 1 + saltlen + 1, sizeof(char));
char *beg = ret;
*beg++ = '$';
*beg++ = version;
*beg++ = '$';
memcpy((void*) beg, (const void*) salt, saltlen + 1);
return ret;
}
void crypt_and_print(const char *passwd, const char *salt_and_version)
{
char *result = crypt(passwd, salt_and_version);
assert(puts(result) != EOF);
}
int main(int argc, char* argv[])
{
if (argc != 4) {
fprintf(stderr, "argc = %d\n", argc);
return 1;
}
char *salt_and_version = GetSaltAndVersion(argv[2][0], argv[3]);
crypt_and_print(argv[1], salt_and_version);
free(salt_and_version);
return 0;
}
I have tried as #Andrey Akhmetov suggested and put the #define onto the first line, but the warnings did not disappear.
The macro _XOPEN_SOURCE is documented in feature_test_macros(7). In particular, the manpage states:
NOTE: In order to be effective, a feature test macro must be defined before including any header files. This can be done either in the compilation command (cc -DMACRO=value) or by defining the macro within the source code before including any headers.
When you include stdio.h, you indirectly include features.h, which uses the feature test macros as defined at that point. In particular, since _XOPEN_SOURCE and friends aren't defined at that point, crypt.h does not declare crypt.
By the time you define _XOPEN_SOURCE it is too late, since features.h has an include guard preventing it from being included twice.
By swapping the order of the first two lines, the code works without raising this warning on my system:
#define _XOPEN_SOURCE
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "$6$2222"));
return 0;
}
Your larger example does not work for a second reason: You wrote _X_OPEN_SOURCE as the name of the macro, while the correct name is _XOPEN_SOURCE.

Custom print function with _TIME_, _FILE_, _FUNCTION_, _LINE_

I have following code in debug.h:
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef DEBUG
int al_debug(const char *format,
const char * time,
const char * file,
const char * function,
int line,
...);
#define debug(fmt, args...) al_debug(fmt, __TIME__, __FILE__, __FUNCTION__, __LINE__, args...)
#else /* IF DEBUG NOT DEFINED*/
#define debug(fmt, ...) /* DO NOT PRINT ANYTHING IF DEBUG IS NOT PRESENT */
#endif /* END OF DEBUG */
#endif /* END OF __DEBUG_H__ */
In debug.c:
#include <stdarg.h>
#include <string.h>
#define __WRAP_FUNCTION__
#include "debug.h"
#ifdef DEBUG
int debug(const char *format,
const char * time,
const char * file,
const char * function,
int line,
...)
{
int done=0;
va_list arg;
va_start(arg, format);
done = vfprintf(stdout, "%s :%s:%s:%d", time, file, function, line);
done += vfprintf(stdout, format, arg);
va_end(arg);
return done;
}
#endif
And after compiling it I am getting following errors:
gcc -g -Wall -DDEBUG -c debug.c -o d_debug.o
debug.c:16:1: error: expected declaration specifiers or ‘...’ before string constant
debug.c:16:1: error: expected declaration specifiers or ‘...’ before string constant
debug.c:11:5: error: expected declaration specifiers or ‘...’ before ‘__FUNCTION__’
debug.c:16:1: error: expected declaration specifiers or ‘...’ before numeric constant
How I can fix this problem? What is problem here? Thank you in advance.
1) Change function name
// int debug(
int al_debug(
2) Use regular fprintf()
// done = vfprintf(stdout, "%s :%s:%s:%d", time, file, function, line);
done = fprintf(stdout, "%s :%s:%s:%d", time, file, function, line);
3) Start at line. Use parameter before ...
// va_start(arg, format);
va_start(arg, line);
4) Pedantic note: add done check for < 0 after each print.
done = fprintf(stdout, "%s :%s:%s:%d", time, file, function, line);
if (done >= 0) {
int done_former = done
done = vfprintf(stdout, format, arg);
if (done >= 0) done += done_former;
}
va_end(arg);
return done;
5) Change args...) to args) #leeduhem
[Edit] to work with no args after format.
int al_debug(const char * time, const char * file, const char * function,
int line, const char *format, ...);
#define debug(...) al_debug(__TIME__, __FILE__, __func__, __LINE__, __VA_ARGS__)
// #leeduhem for __VA_ARGS__
#else /* IF DEBUG NOT DEFINED*/
#define debug(...) /* DO NOT PRINT ANYTHING IF DEBUG IS NOT PRESENT */
#endif /* END OF DEBUG */
int al_debug(const char * time, const char * file, const char * function,
int line, const char *format, ...) {
int done = 0;
va_list arg;
va_start(arg, format); // change to `format`
...
Fixed version:
debug.h
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef DEBUG
int al_debug(const char *time, const char *file, const char *func, int line, const char * format, ...);
#define debug(...) al_debug(__TIME__, __FILE__, __func__, __LINE__, __VA_ARGS__)
#else /* IF DEBUG NOT DEFINED*/
#define debug(...) /* DO NOT PRINT ANYTHING IF DEBUG IS NOT PRESENT */
#endif /* END OF DEBUG */
#endif /* END OF __DEBUG_H__ */
debug.c
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#define __WRAP_FUNCTION__
#include "debug.h"
#ifdef DEBUG
int al_debug(const char *time, const char *file, const char *func, int line, const char *format, ...)
{
int done=0;
va_list arg;
va_start(arg, format);
done = fprintf(stdout, "%s :%s:%s:%d: ", time, file, func, line);
done += vfprintf(stdout, format, arg);
va_end(arg);
return done;
}
#endif
test.c
#include <stdio.h>
#include <stdlib.h>
#include "debug.h"
void foo(void)
{
debug("debugg...\n");
debug("%s and %d\n", "debug information", 42);
}
int
main(int argc, char *argv[])
{
foo();
exit(EXIT_SUCCESS);
}
Testing:
$ gcc -g -Wall -I. -DDEBUG debug.c test.c
test.c: In function ‘main’:
test.c:12:10: warning: unused parameter ‘argc’ [-Wunused-parameter]
test.c:12:22: warning: unused parameter ‘argv’ [-Wunused-parameter]
$ ./a.out
10:46:40 :test.c:foo:8: debugg...
10:46:40 :test.c:foo:9: debug information and 42
$ gcc -g -Wall -I. debug.c test.c
test.c: In function ‘main’:
test.c:12:10: warning: unused parameter ‘argc’ [-Wunused-parameter]
test.c:12:22: warning: unused parameter ‘argv’ [-Wunused-parameter]
$ ./a.out
$
A few links that may be helpful:
6.20 Macros with a Variable Number of Arguments
6.47 Function Names as Strings

conflicting types for main and previous definition of main was here when compiling with make

I'm trying to compile three files together, having one main method in passweb.c.
heres passweb.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <cipher.c>
#include <menu.c>
long pointer;
char *createRecord(char *name, char *password, char *type);
char *file = "password.csv";
int main(int argc, char *argv[]){
if(fopen(file,"r")==NULL){
FILE *newFile = fopen(file,"w+");
fclose(newFile);
}
if(strcmp(argv[0],"-menu")==1){
menu();
}
else if(strcmp(argv[0],"-add")==1){
add(argv[1], argv[2], argv[3]);
}
else if(strcmp(argv[0],"-edit")==1){
edit(argv[1],argv[2],argv[3],argv[4],argv[5],argv[6]);
}
}
and cipher.c
#include <stdio.h>
#include <stdlib.h>
int Encrypt(char *fileName){
int offset=5;
Shift(fileName, offset);
}
int Decrypt(char *fileName){
int offset=-5;
Shift(fileName, offset);
}
the makefile:
passweb: passweb.c menu.c cipher.c
gcc -o passweb passweb.c menu.c cipher.c -I.
the errors:
passweb.c:10: error: conflicting types for ‘main’
./cipher.c:3: error: previous definition of ‘main’ was here
I can't figure out what I'm doing wrong.
Thank you in advance for your time!!
Don't include source files into source files. Get rid of the following:
#include <cipher.c>
#include <menu.c>
The way you've written it, you're compiling menu.c and cipher.c twice. First when you compile passweb.c, and again when you compile menu.c and cipher.c.

va_list arguments not working as expected

I've been tracing a problem that I've narrowed down to this skeleton:
#include <unistd.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct __log_file_details {
FILE *fp ;
char *name ;
} log_file_details_t;
typedef struct __log_files {
char is_open;
log_file_details_t lf[3];
void (*open_log)(struct __log_files *ctl);
void (*close_log)(struct __log_files *ctl);
} log_files_t ;
int write_log(const int file_nbr, log_files_t *ctl, char *log_this, ...);
void close_log(log_files_t *ctl);
void open_log(log_files_t *ctl);
// Here we go...
int main(int argc, char *argv[]) {
log_files_t log_ctl = {
0,
{ {NULL, NULL}, {NULL, NULL}, {NULL, NULL} },
&open_log,
&close_log
};
write_log(0, &log_ctl, "foo"); // That's it.
return 0;
}
void open_log(log_files_t *ctl) {}
void close_log(log_files_t *ctl) {}
int write_log(const int file_nbr, log_files_t *ctl, char *log_this, ...)
{
int rc;
/* ... */
rc = 0;
}
When I compile this code using gdb -g -o foo foo.c it works on most of my linux systems.
However, I have an ARM device (actually, a Netgear Stora running Linux) on which it fails miserably.
On that device, if I use GDB to step through this code, when write_log executes (line 58), I see:
Breakpoint 1, write(log(file_nbr=-1092220616, ctl=0x0, log_this=0xbee60ac4 "-garbage-") at foo.c:58
(where -1092220616 is a varying value, and -garbage- tends to contain a bunch of control characters.)
I don't know how to determine if this is a runtime problem (one of the libraries?), a problem with one of the standard headers, a gcc problem, or something else. What might I do in order to identify and resolve this problem?
If I remove the va_list definition of write_log, all works well, but of course that's not what I want.)
You need to properly clean up the variable args in your function:
int write_log(const int file_nbr, log_files_t *ctl, char *log_this, ...)
{
int rc;
va_list vl;
va_start(vl,log_this);
/* ... */
va_end(vl);
rc = 0;
}

Resources