And here’s another example of what breaking the program looks like:
It doesn’t even seem to exit on the error!
And here’s another example of what breaking the program looks like:
It doesn’t even seem to exit on the error!
Do you use valgrind? Does it have any output that could help?
No… I’m not sure how to use Valgrind. By the way, I get similar behavior in exercise 25 with MAX_DATA
set to 5
. I can type in dddddddddd20
to fill all the fields:
If valgrind is installed it’s a simple command for the basic use:
$ valgrind ./ex24
But I usually run with a couple extra switches:
$ valgrind --leak-check=full --track-origins=yes ./ex24
Also if you’ve made it to ex24 without using gdb, I’m impressed.
Thanks so much, I’m installing Valgrind right now and then I’ll try that.
I’ve used a little GDB, but I’m still learning. No Valgrind, though. It seems to be happy…
EDIT: I get the same response with your flags
Worth a shot. Sometimes it catches some weird memory runoff’s and tracks em down. I’m a student too. But gdb and valgrind are both very valuable. gdb is especially awesome once you learn a few commands like explore
, print
, break
, info
, watch
, make
, run
, start
, step
, next
, continue
, finish
, set
, delete
, clear
.
EDIT: I could still be forgetting some. But those all have been good to me in general gdb usage.
Yeah, break
is SUPER useful I’ve found. Here’s the output of Valgrind -> [|]
Thanks for the help so far!
I’d say it would be well worth your time at this point to play around in gdb, use the help
and apropos
commands to get familiar with gdb commands. The more you dabble the more you see what I mean. That gdb is very powerful if you know your way around.
Ok, thank you. I will do that.
As for the issue with fgets, that’s beyond me lol. I’m not to that chapter yet. But I’m sure someone can shine some light on things.
That’s super bizarre. The man page says that fgets will add the \0 terminator if the fgets does NOT have an error. It looks like one of three things:
Try #2, as a quick fix. Remember you can easily zero out a struct by setting one attribute to 0 or NULL on initialization:
struct MyThing stuff = {.name = NULL};
You’ll have to forgive me if that syntax is off since I’m a little rusty on C these days. If none of that works and you’re using malloc to make the data structs then use calloc instead. Do NOT try to use memset to zero out the memory. That produces errors and you’ll get the size wrong all the time.
Thanks! I tried initializing the strings with { 0 }
but that didn’t seem to do anything… Initializing them with 0
and NULL
didn’t work either. It may very well be the third thing you said. I noticed that the minimum number of characters needed to overflow is 8, not 10 (which is the value of MAX_DATA
). Any ideas how I might fix that? I’ll try some things meanwhile. I’m also pretty sure it’s a problem with input, because it doesn’t actually seem to be overflowing in memory, and Valgrind is happy as a clam…
UPDATE: Telling fgets()
that the size is MAX_DATA - 2
didn’t work
Check this out, maybe it’ll clarify the string initialization?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **strings;
int main(int argc, char *argv[])
{
strings = calloc(100, sizeof(char) * 100);
strings[0] = calloc(100, sizeof(char));
strings[0] = strncpy(strings[0], "Something\n", 100);
strings[1] = calloc(100, sizeof(char));
strings[1] = strncpy(strings[1], "Something else\n", 100);
int i = 0;
for (i = 0; i < 100; i++) {
printf(strings[i]);
free(strings[i]);
}
free(strings);
}
I did some research and the problem doesn’t seem to be what I originally thought. fgets()
is correctly reading in the string up to MAX_DATA
and is correctly terminating it with '\0'
, but the excess characters I typed are being stored in some buffer and entered into the next fgets()
calls.
I was able to solve it by checking whether the input contained "\n"
and if so flushed STDIN. Here’s a snippet of the code:
// ...
void flush_stdin() {
int ch;
ch = fgetc(stdin);
do { ch = fgetc(stdin); } while (ch != EOF && ch != '\n');
}
int main(int argc, char *argv[]) {
Person you = { .age = 0 };
int i = 0;
char *in = NULL;
printf("What's your first name? ");
in = fgets(you.first_name, MAX_DATA - 1, stdin);
check(in != NULL, "Failed to read first name");
if (!strstr(you.first_name, "\n")) flush_stdin();
printf("What's your last name? ");
in = fgets(you.last_name, MAX_DATA - 1, stdin);
check(in != NULL, "Failed to read last name");
if (!strstr(you.last_name, "\n")) flush_stdin();
printf("How old are you? ");
int rc = fscanf(stdin, "%d", &you.age);
check(rc > 0, "You have to enter a number");
printf("What color are your eyes:\n");
for (i = 0; i <= OTHER_EYES; i++) {
printf("%d) %s\n", i + 1, EYE_COLOR_NAMES[i]);
}
printf("> ");
int eyes = -1;
rc = fscanf(stdin, "%d", &eyes);
check(rc > 0, "You have to enter a number");
you.eyes = eyes - 1;
check(you.eyes <= OTHER_EYES && you.eyes >= 0, "Do it right, that's not an option");
// ...
No, I don’t think that’s it either. There is something you’re doing that either doesn’t initialize the variables correctly, OR is pointing fgets at the wrong thing. Try this:
That’s my code for the problem. Take that, compile it and run it just like you’re doing here. If mine works and yours doesn’t then do this:
diff zeds_ex24.c my_ex24.c
That’ll tell you what’s wrong. Then, report back because I am dying out of curiosity.
I have the same original problem with your code as well… so weird! This was the only thing that helped.
That means your computer is super weird 'cause that code works on my machines. I mean, unless something changed in C since then so maybe I should go try it. Can you do this for me:
I’ll go try it out.
MAX_DATA
at the top to 10
make ex24
./ex24
dddddddddddddddddddddddddddddddddddddddddddddddddddddddd
OS:
Ubuntu 18.04.1 x86_64
Output of gcc -v
:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.3.0-27ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
EDIT: Updated ex22 to ex24
Heres what I get:
bruda@cyborg ~/LCTHW/Lectures/ex24 (git)-[master] % ./ex24
What's your First Name? dddddddddddddddddddddddddddddddddddddddddddddddddddddd
[ERROR] (ex24.c:39: errno: None) You have to enter a number.
What's your Last Name? How old are you? %
bruda@cyborg ~/LCTHW/Lectures/ex24 (git)-[master] %
MY gcc -v
:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp --enable-cet=auto
Thread model: posix
gcc version 8.2.1 20180831 (GCC)