[SOLVED] C - assert fails on 2nd run of same function.
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
void file_reverse_output(FILE * file,
FILE * newfile,
char * type)
{
// we don't check newfile as NULL is a valid value
assert(file);
// declare & initialize
long int len = file_num_lines(file);
long int maxstr = 0;
if (string_is_valid(type, "memsave")) {
maxstr = file_longest_string(file);
printf("memsave active\n");
} else if (string_is_valid(type, "nomemsave")) {
// this section fails assertion on file at getline_mem_alloc
// below
maxstr = MAX_BUFFER;
printf("standard buffer active\n");
} else {
printf("specify memsave / nomemsave\n");
exit(1);
}
char buffer[len][maxstr + 1];
// initialize array. this solved an uninitialized value
// error in valgrind down in the print loop. there may
// be a better way to solve the error. this isn't the
// fastest i'm guessing
for (int i = 0; i <= len; i++) {
for (int j = 0; j <= maxstr; j++) {
buffer[i][j] = '\0';
}
}
// loop through each line in text file, put in buffer for
// future stdout / fprintf
for (int i = 0; i < len; i++) {
char * ptr = getline_mem_alloc(file);
if (!ptr) {
break;
}
// load lines into buffer and clear pointer
strncpy(buffer[i],
ptr,
maxstr - 1);
clear_char_ptr(ptr);
}
// reset file for next usage
rewind(file);
// print buffer in reverse order to either stdout or newfile
for (int j = len - 1; j >= 0; j--) {
no_more_newline(buffer[j]);
if (newfile == NULL) {
printf("%s\n",
buffer[j]);
} else {
fprintf(newfile,
"%s\n",
buffer[j]);
}
}
// rewind temp for next usage
if (newfile) {
rewind(newfile);
}
}
I started screwing around with minimizing memory usage. Not fast but keeps the buffer only as big as it needs to be. My problem is when I run it from this test.c file.
Code:
#include <stdio.h>
#include <jmgeneral.h>
#include <string.h>
int main()
{
FILE * file = fopen("testfile.txt", "r");
if (!file) {
printf("failed to open\n");
return(1);
}
// this one works fine
file_reverse_output(file, NULL, "memsave");
// this run fails file assertion when it gets to
// getline function in file_reverse_output
file_reverse_output(file, NULL, "nomemsave");
fclose(file);
file = NULL;
return(0);
}
I can't figure why it works the first time then falls over the 2nd.
if (string_is_valid(type, "memsave")) {
// works when run longest string on file
maxstr = file_longest_string(file);
} else if (string_is_valid(type, "nomemsave")) {
// doesn't work with static buffer number...
maxstr = MAX_BUFFER;
} else {
printf("specify memsave / nomemsave\n");
exit(1);
}
when I call the function below it works. but won't work with a static buffer size, in this case my header is saying 1024.
Code:
long int file_longest_string(FILE * file, long int lines)
{
assert(file);
// declare & initialize
long int len = 0;
// loop through each line in file.
// set return value to longest string in file
for (int i = 0; i < lines; i++) {
char * ptr = getline_mem_alloc(file);
no_more_newline(ptr);
long int j = strlen(ptr);
if (j > len) {
len = j;
}
clear_char_ptr(ptr);
}
// clean up & return
rewind(file);
return(len + 1);
}
Okay. For what it's worth I don't know how I missed that on copy, maybe I didn't copy the most recent like I thought I did. :/
Code:
if (string_is_valid(type, "memsave")) {
// works when function run on file for maxstr
maxstr = file_longest_string(file, len);
} else if (string_is_valid(type, "nomemsave")) {
// doesn't work with static buffer number...
maxstr = MAX_BUFFER;
} else {
printf("specify memsave / nomemsave\n");
exit(1);
}
Solved somewhat although I don't understand why it worked. I spent the last half hour or so inserting printf statements to return the pointer address. Moving them around until I isolated the section. For.... whatever reason? when I ran my array initialization loop it would null the file pointer. I'm at a loss as to the why... But it's fixed and clean pass through valgrind. Gonna test in a few other tools. Thank you for your assistance.
char buffer[len][maxstr + 1];
// initialize array. commented out because it changes the file
// pointer to null. can't explain why. defintely a question
// mark but this function in both modes passes valgrind cleanly
// initialize array. commented out because it changes the file
// pointer to null. can't explain why. defintely a question
// mark but this function in both modes passes valgrind cleanly
// now.
/*for (int i = 0; i <= len; i++) {
for (int j = 0; j <= maxstr; j++) {
You need either "buffer[len + 1][maxstr + 1]", or "for (int i = 0; i < len; i++) {..."
I think Valgrind can't (always?) notice overruns of stack variables, so that's why it misses this.
It's difficult to help here because so much is missing and so much is not shown private functions.
Sorry but one needs to view the git repo or various other threads from the OP, it makes the effort difficult to assess for helping. Perhaps if you can provide a more clear summary in the original question.
Also you used 3 pointers, which are copies, modifying the contents may cause problems but you can't nullify a passing argument that is a stack copy of the original pointer. Therefore your problem was elsewhere.
Probably said it before but gdb would help immensely in your diagnostics and debugging.
I've seen this a lot, people start, do basic stuff, then they add a lot of their own experimentation, racing forwards with "can I do this", but overlooking better design and debug practices, instead running into problems where they could be solved fairly quickly or not exist if the fundamentals were concentrated on better.
I'm still looking for a good way to find what I need in the standard libraries. So far I can just look at the headers and check the man pages on what I think might work. But then I get lazy and try to write it myself. Also still learning gdb. I'm trying to find that 3 pointer thing you mentioned but not seeing it. I don't doubt what you said but I'm clueless thus far. Still working on iut though.
*EDIT* I am also taking some time and learning GDB via CLI. Kept looking for a gui but gave up. Starting to see the value in using a text editor + cli stuff > ide. Base tools are more likely to not crash. Not that that is an issue with Debian in the first place for the most part of course...
Last edited by jmgibson1981; 10-19-2023 at 10:14 PM.
I'm still looking for a good way to find what I need in the standard libraries. So far I can just look at the headers and check the man pages on what I think might work. But then I get lazy and try to write it myself. Also still learning gdb. I'm trying to find that 3 pointer thing you mentioned but not seeing it. I don't doubt what you said but I'm clueless thus far. Still working on iut though.
Each of the three arguments is a copy of a pointer, tyerefore altering any of them will not have impact outside of your function.
*EDIT* I am also taking some time and learning GDB via CLI. Kept looking for a gui but gave up. Starting to see the value in using a text editor + cli stuff > ide. Base tools are more likely to not crash. Not that that is an issue with Debian in the first place for the most part of course...
char a[10];
void main() {
int i;
char b;
for (i=0; i<=10; i++) { b=a[i]; }
}
valgrind can do it, just need to add a command line flag:
Code:
/tmp$ valgrind --tool=exp-sgcheck ./a.out
==3182== exp-sgcheck, a stack and global array overrun detector
==3182== NOTE: This is an Experimental-Class Valgrind Tool
==3182== Copyright (C) 2003-2015, and GNU GPL'd, by OpenWorks Ltd et al.
==3182== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==3182== Command: ./a.out
==3182==
==3182== Invalid read of size 1
==3182== at 0x4004FF: main (a.c:6)
==3182== Address 0x60103b expected vs actual:
==3182== Expected: global array "a" of size 10 in object with soname "NONE"
==3182== Actual: unknown
==3182== Actual: is 0 after Expected
==3182==
==3182==
==3182== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.