The function adds a tab defined by the parameter pad function. Problems:

  1. The first problem is that when I try to free up the main array that this function returns, I get an error. In debug mode, I get the following message:

    Signal received: SIGABRT (Aborted) For main program, PID 8 688. You can ignore the signal or send it, or continue or pause the process

Also in the by 0x402509: test_indent (test_source.c:178) line by 0x402509: test_indent (test_source.c:178) tests in test_intend valgrind — and tests free up memory, so this is the same problem.

  1. The second problem is visible from Valgrind : he doesn't like malloc and strncpy . Using memcpy instead of strncpy does not change anything. After each mention of intend in Valgrind I added a line in which he didn’t like something.

This task is part of the C language courses, and when I send the code to the server, memory leaks, etc. are checked there using Valgrind . When I try to send this particular function to the server, I get a failure message "Early exit with return value 1". I would also like to know what the host stacktrace with a lot of question marks?

I will be glad to any help!

 //------------- Valgrind validations ------------------ ==396== Invalid write of size 1 ==396==    at 0x4C2C884: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==396==    by 0x401E7C: indent (polisher.c:116) c:116 strncpy(dest + dest_offset, pad, pad_len + 1); ==396==    by 0x402556: test_indent (test_source.c:178) ==396==    by 0x406B07: srunner_run (in /tmc/test/test) ==396==    by 0x402BA9: tmc_run_tests (tmc-check.c:134) ==396==    by 0x402844: main (test_source.c:235) ==396==  Address 0x59122c0 is 0 bytes after a block of size 144 alloc'd ==396==    at 0x4C2AD10: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==396==    by 0x401D2B: indent (polisher.c:80) c:80 dest = calloc(strlen(input) + 1, sizeof(char)); ==396==    by 0x402556: test_indent (test_source.c:178) ==396==    by 0x406B07: srunner_run (in /tmc/test/test) ==396==    by 0x402BA9: tmc_run_tests (tmc-check.c:134) ==396==    by 0x402844: main (test_source.c:235) ==396== ==396== Invalid write of size 1 ==396==    at 0x401EF4: indent (polisher.c:127) c:127 dest[dest_offset++] = c; ==396==    by 0x402556: test_indent (test_source.c:178) ==396==    by 0x406B07: srunner_run (in /tmc/test/test) ==396==    by 0x402BA9: tmc_run_tests (tmc-check.c:134) ==396==    by 0x402844: main (test_source.c:235) ==396==  Address 0x59122c0 is 0 bytes after a block of size 144 alloc'd ==396==    at 0x4C2AD10: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==396==    by 0x401D2B: indent (polisher.c:80) c:80 dest = calloc(strlen(input) + 1, sizeof(char)); ==396==    by 0x402556: test_indent (test_source.c:178) ==396==    by 0x406B07: srunner_run (in /tmc/test/test) ==396==    by 0x402BA9: tmc_run_tests (tmc-check.c:134) ==396==    by 0x402844: main (test_source.c:235) ==396== ==396== Invalid write of size 1 ==396==    at 0x401E45: indent (polisher.c:112) c:112 dest[dest_offset++] = c; ==396==    by 0x402556: test_indent (test_source.c:178) ==396==    by 0x406B07: srunner_run (in /tmc/test/test) ==396==    by 0x402BA9: tmc_run_tests (tmc-check.c:134) ==396==    by 0x402844: main (test_source.c:235) ==396==  Address 0x59122cb is 11 bytes after a block of size 144 alloc'd ==396==    at 0x4C2AD10: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==396==    by 0x401D2B: indent (polisher.c:80) c:80 dest = calloc(strlen(input) + 1, sizeof(char)); ==396==    by 0x402556: test_indent (test_source.c:178) ==396==    by 0x406B07: srunner_run (in /tmc/test/test) ==396==    by 0x402BA9: tmc_run_tests (tmc-check.c:134) ==396==    by 0x402844: main (test_source.c:235) ==396== ==396== Invalid write of size 1 ==396==    at 0x4C2C7FC: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==396==    by 0x401E7C: indent (polisher.c:116) c:116 strncpy(dest + dest_offset, pad, pad_len + 1); ==396==    by 0x402556: test_indent (test_source.c:178) ==396==    by 0x406B07: srunner_run (in /tmc/test/test) ==396==    by 0x402BA9: tmc_run_tests (tmc-check.c:134) ==396==    by 0x402844: main (test_source.c:235) ==396==  Address 0x59122cc is 12 bytes after a block of size 144 alloc'd ==396==    at 0x4C2AD10: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==396==    by 0x401D2B: indent (polisher.c:80) c:80 dest = calloc(strlen(input) + 1, sizeof(char)); ==396==    by 0x402556: test_indent (test_source.c:178) ==396==    by 0x406B07: srunner_run (in /tmc/test/test) ==396==    by 0x402BA9: tmc_run_tests (tmc-check.c:134) ==396==    by 0x402844: main (test_source.c:235) ==396== valgrind: m_mallocfree.c:304 (get_bszB_as_is): Assertion 'bszB_lo == bszB_hi' failed. valgrind: Heap block lo/hi size mismatch: lo = 208, hi = 2461329846612619888. This is probably caused by your program erroneously writing past the end of a heap block and corrupting heap metadata.  If you fix any invalid writes reported by Memcheck, this assertion failure will probably go away.  Please try that before reporting this as a bug. host stacktrace: ==396==    at 0x380A48EF: ??? (in /usr/lib/valgrind/memcheck-amd64-linux) ==396==    by 0x380A49E4: ??? (in /usr/lib/valgrind/memcheck-amd64-linux) ==396==    by 0x380A4B66: ??? (in /usr/lib/valgrind/memcheck-amd64-linux) ==396==    by 0x380B170D: ??? (in /usr/lib/valgrind/memcheck-amd64-linux) ==396==    by 0x3809DC93: ??? (in /usr/lib/valgrind/memcheck-amd64-linux) ==396==    by 0x3809C73B: ??? (in /usr/lib/valgrind/memcheck-amd64-linux) ==396==    by 0x380A05BA: ??? (in /usr/lib/valgrind/memcheck-amd64-linux) ==396==    by 0x3809BCB2: ??? (in /usr/lib/valgrind/memcheck-amd64-linux) ==396==    by 0x808D20101: ??? ==396==    by 0x808B95EEF: ??? ==396==    by 0x38072A6F: ??? (in /usr/lib/valgrind/memcheck-amd64-linux) ==396==    by 0x401E7C: indent (polisher.c:116) sched status:  running_tid=1 Thread 1: status = VgTs_Runnable ==396==    at 0x4C2C7FC: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==396==    by 0x401EBE: indent (polisher.c:122) c:122 strncpy(dest + dest_offset, pad, pad_len + 1); ==396==    by 0x402556: test_indent (test_source.c:178) ==396==    by 0x406B07: srunner_run (in /tmc/test/test) ==396==    by 0x402BA9: tmc_run_tests (tmc-check.c:134) ==396==    by 0x402844: main (test_source.c:235) Note: see also the FAQ in the source distribution. It contains workarounds to several common problems. In particular, if Valgrind aborted or crashed after identifying problems in your program, there's a good chance that fixing those problems will prevent Valgrind aborting or crashing, especially if it happened in m_mallocfree.c. If that doesn't help, please report this bug to: www.valgrind.org In the bug report, send all the above text, the valgrind version, and what OS and version you are using.  Thanks. 

================================================= =======================

 /* Indent the C-code at memory block <indent>. String <pad> represents * one block of indentation. Only opening curly braces '{' increase the * indentation level, and closing curly braces '}' decrease the indentation level. * Return the pointer to the code after modification. * Calling code is responsible of freeing only the memory block returned by * the function. */ char *indent(char *input, const char *pad) { size_t pad_len = strlen(pad); size_t pad_level = 0; char *dest; if(!input) return NULL; size_t dest_len = strlen(input); size_t dest_offset = 0; char c; dest = calloc(strlen(input) + 1, sizeof(char)); if(!dest) return NULL; while(isspace(*input)) input++; while(*input) { c = *input; if(c == '{') pad_level++; if(c == '}') pad_level--; if(c == '\n') { while(isspace(*input)) input++; if(!*input) { dest[dest_offset++] = c; break; } if((pad_len * pad_level) > (dest_len - dest_offset)) { char *ptr = realloc(dest, dest_len * 2); if(!ptr) { free(dest); return NULL; } dest_len *= 2; dest = ptr; } dest[dest_offset++] = c; if(*input != '}') for(unsigned int q = 1; q <= pad_level; q++) { strncpy(dest + dest_offset, pad, pad_len + 1); dest_offset += pad_len; } else for(unsigned int q = 1; q <= pad_level - 1; q++) { strncpy(dest + dest_offset, pad, pad_len + 1); dest_offset += pad_len; } continue; } dest[dest_offset++] = c; input++; } dest[dest_offset] = 0; return dest; } 

    2 answers 2

    1. realloc - the operation of allocating additional memory.

      The memory allocation operations themselves are quite resource intensive. As I see in the code, this is all done in a loop ... If you try to get away from it (once to allocate a large piece of memory), then the performance will increase.

    2. It seems the code is duplicated. I would take it to separate functions and call them.

    3. I can be mistaken, but access by index is slower than access to an element through offset.

    4. You can also try parallelizing the process. Each thread takes its many lines and works with it.

    Most likely it will be enough to correct the first paragraph.

    • 2
      The third point - really wrong. the index in the array is the same offset. processor just doesn't have other access methods - Mike
    • @Mike edited - problems still remained. - JasonUrban

    I wouldn’t even try to figure out so tricked someone else’s source code. The task is quite simple, who prevents you from writing yourself because it is clear and convenient for you?

    That's what literally pounced on my knee. The code is not perfect, of course. From obvious flaws - the occurrence } and { is not checked in lines, and there is something to bring to mind. But clearly the same clearly:

     char *indent( const char *src, const char *pad ) { size_t pad_len = strlen( pad ); size_t pad_level = 0; char *dest; size_t dest_len = strlen( src ); size_t dest_offset = 0; char c; size_t i; /* Плохая, очень плохая, очень-очень-очень плохая идея - * раскурочивать исходную строку. * Лучше выделим отдельную память для результата: */ dest = malloc( dest_len + 1 ); if( !dest ) { return NULL; } while( isspace( *src ) ) { src++; } while( *src ) { c = *src; if( c == '\n' ) { while( isspace( *src ) ) { src++; } if( !*src ) { break; } /* Проверяем размер строки-приёмника только здесь. * В других местах смысла нет, мы заранее заложились * на длину исходной строки как минимум. */ if( ( pad_len * pad_level ) > ( dest_len - dest_offset ) ) { /* Увеличиваем строку-приёмник в 2 раза. Некоторые * источники рекомендуют в полтора раза. Ну а если * совсем с памятью туго, можно и на величину * (pad_len*pad_level), или просто на какую-то * фиксированную величину. Только скорости это уж точно * не добавит. */ char *ptr = realloc( dest, dest_len * 2 ); if( !ptr ) { free( dest ); return NULL; } dest_len *= 2; dest = ptr; } dest[dest_offset++] = c; if( *src == '}' ) { if( pad_level ) { pad_level--; } else { /* обработать ошибку: закрывающая скобка не на месте */ } } for( i = 0; i < pad_level; i++ ) { memcpy( dest + dest_offset, pad, pad_len ); dest_offset += pad_len; } continue; } /* Здесь я немного не понял, скобки в любом месте влияют на * уровень отступов, или только если они встречаются в начале * строки. Для примера и так сойдёт. */ if( c == '}' ) { if( pad_level ) { pad_level--; } else { /* обработать ошибку: закрывающая скобка не на месте */ } } else if( c == '{' ) { pad_level++; } dest[dest_offset++] = c; src++; } dest[dest_offset] = 0; return dest; } 

    PS By the way, for answering questions of the level "where it slows down and what to optimize", a separate class of programs was invented. They are called "profilers" and should be in the arsenal of any sichnik, along with the compiler, linker and debugger.

    • edited - problems still remained. - JasonUrban
    • For some reason, the strncpy(dest + dest_offset, pad, pad_len + 1); strings strncpy(dest + dest_offset, pad, pad_len + 1); do not suit strncpy(dest + dest_offset, pad, pad_len + 1); , dest = calloc(strlen(input) + 1, sizeof(char)); , dest[dest_offset++] = c; . - JasonUrban
    • The first thing that catches your eye: for some reason, you copy pad_len+1 byte instead of pad_len . Most likely, this is where the memory gets stuck, by an extra byte for each level pad_level . - gottar
    • already fixed - anyway - JasonUrban
    • Then bring a set of input data. My valgrind doesn't catch anything. - gottar