c - How to detect instances where code accidentally creates a pointer to a pointer? -
in doing wholesale refactoring, i've come across instances i've made same mistake. have accidentally passed pointer pointer instead of pointer.
code explains best. /* oops */
below.
the struct:
struct my_struct { int x; int y; int z; int value; }
initialize function:
void initialize(struct my_struct *s) { s->x = 0; s->y = 0; s->z = 0; s->value = 0; }
the original function:
struct my_struct do_something() { struct my_struct s; initialize(&s); s.value = 27; return s; }
the new function
void do_something(struct my_struct *s) { initialize(&s); /* oops! */ s->value = 27; }
it should have been:
void do_something(struct my_struct *s) { initialize(s); /* fixed */ s->value = 27; }
is there way, maybe compiler flag or linter can me locate these oopsies?
notes: i'm using gcc (but if compiler or linter can find this, please tell)
i'm using these compiler flags , don't catch it:
cflags = \ -std=c89 \ -pedantic \ -pedantic-errors \ -werror \ -wextra \ -wmissing-prototypes \ -wall \ -wold-style-definition \ -wdeclaration-after-statement \ -wundef \ -wpointer-arith \ -wcast-qual \ -wcast-align \ -wfloat-equal \ -wno-missing-braces
i have prototypes in header everything.
it's not standard picked -- c90. c99 , c11 take too.
$ gcc --version gcc (gcc) 6.1.1 20160621 (red hat 6.1.1-3)
passing pointer pointer pointer expected must cause compiler error. cannot reproduce example suggesting (gcc 5.4.0, c99).
but there situation can cause kind of error:
foo.h:
struct foo { int dummy; };
main.c:
#include "foo.h" void init(void *); int main() { struct foo f; struct foo * fp = &f; init(&f); init(&fp); return 0; }
init.c:
#include "foo.h" // need prototype because otherwise -wmissing-prototypes issues warning // such code not uncommon, though, when e.g. there // c preprocessor macros defining kinds of functions. void init(struct foo *f); void init(struct foo *f) { f->dummy = 42; }
this compiles fine without warning. translation unit main.c
sees (wrong) declaration void init(void *)
, emits no warning when passing different pointer types (as they're implicitly convertible void *
). since c compilers don't mangle parameter types symbols of resulting object files, linker happily resolve reference function init
main.o
function symbol init
in init.o
.
[nix-shell:/tmp/wtf]$ nm init.o 0000000000000000 t init [nix-shell:/tmp/wtf]$ nm main.o u _global_offset_table_ u init 0000000000000000 t main u __stack_chk_fail
c++ compilers do mangle parameter types symbols, thus:
[nix-shell:/tmp/wtf]$ lang= g++ -wall -wextra main.c init.c /run/user/1000/cctwt0nl.o: in function `main': main.c:(.text.startup+0x1d): undefined reference `init(void*)' main.c:(.text.startup+0x27): undefined reference `init(void*)' collect2: error: ld returned 1 exit status
note: i'm not suggesting compile c code c++ compiler. don't that, please.
Comments
Post a Comment