[isogram] Can't Test as Segmentation fault (core dumped)

Dear Exercism community,
I was running test on my code iteration for Isogram (C track) exercise.
But I receive

make: *** [makefile:22: test] Segmentation fault (core dumped)

Is it an issue in test routine, or is it my code that generate the error?

Thanks in advance

P.S.: attaching my isogram.c

#include "isogram.h"
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>

bool is_isogram(const char phrase[]) {

    // bool isogram = true;
    unsigned int stringlen = strlen(phrase);
    char phrasetmp[stringlen];
    char temp;

    // copy phrase in phrasetmp
    strcpy(phrasetmp, phrase);
   
    // all characters in lowercase
    for (unsigned int index = 0; index < stringlen; index++) {
        phrasetmp[index] = tolower(phrasetmp[index]);
    }

    // sort characters in string
    for (unsigned int index = 0; index < stringlen-1; index++) {
        for (unsigned int jndex = index+1; jndex < stringlen; jndex++) {
            if (phrasetmp[index] > phrasetmp[jndex]) {
                temp = phrasetmp[index];
                phrasetmp[index] = phrasetmp[jndex];
                phrasetmp[jndex] = temp;
             }
          }
       }

    // if two following characters are the same, set isogram false
    for (unsigned int index = 0; index < stringlen; index++) {
        if (phrasetmp[index] == phrasetmp[index + 1]) return false;
    }
   
    return true;    
}

and isogram.h

#ifndef ISOGRAM_H
#define ISOGRAM_H

#include <stdbool.h>

bool is_isogram(const char phrase[]);

#endif

The error is likely in your code. If it were in the test, then this would fail for all the other students. What is the command you ran? Is there more context in the error message?

There are two issues in the code:

  • The array phrasetmp has a length of strlen(phrase). But the strcpy() copies all the characters of the phrase and the terminating null-byte, writing past the end of the array.
  • Similarly, the final iteration of the last loop accesses phrasetmp at index + 1 which is stringlen and one past the end of the array.

BTW: If you use the exercism CLI to download the exercise and solve it on your computer you can submit incomplete or failing solutions and ask for clarification or assistance.

Edit: I forgot another (subtle) issue: This solution passes a char to tolower(). But tolower() (like the other functions from <ctype.h>) takes an int as its parameter and its behavior is undefined if its argument is neither representable by an unsigned char nor equal to EOF. You should never pass a char or a signed char to tolower() but always cast it to unsigned char first (see also cppreference).
That didn’t cause the segment fault because the tests only use ASCII characters but it’s something that you should be aware of.

One more thing:

Take a close look at the tests, especially test_null(). You will probably have to handle that as a special case.

Have fun!

Got it! Thank you so much!

Thanks for support! I am running just through the online editor sandbox, I was evaluating if it was an error in the Makefile that covers tests… I’ll take a closer look to my code… ;)

In addition to the “out of index array error” you highlighted, the core dump was returned by the miss coverage of case:
if (!phrase) return false;

Thanks again for the hint! :D

As a general debugging measure when you get something like

make: *** [test] Segmentation fault

Its probably a memory access bug. The make file has memcheck target that builds the tests with Address Sanitizer(ASAN) which catches most of these bugs. Example with your buggy code

$ make memcheck
Compiling memcheck
test_isogram.c:107:test_empty_string:PASS
ASAN:DEADLYSIGNAL
=================================================================
==3362==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f1276b03461 bp 0x7fff44ab3f20 sp 0x7fff44ab3698 T0)
==3362==The signal is caused by a READ memory access.
==3362==Hint: address points to the zero page.
    #0 0x7f1276b03460  (/lib/x86_64-linux-gnu/libc.so.6+0x18e460)
    #1 0x7f1276db757b  (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5157b)
    #2 0x555a5b806783 in is_isogram isogram.c:12
    #3 0x555a5b806a91 in test_null test_isogram.c:21
    #4 0x555a5b8065b1 in UnityDefaultTestRun test-framework/unity.c:1837
    #5 0x555a5b806d52 in main test_isogram.c:108
    #6 0x7f1276996c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
    #7 0x555a5b802b89 in _start (/home/sudhakar/tools/exercism/c/isogram/memcheck.out+0x2b89)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libc.so.6+0x18e460)
==3362==ABORTING
makefile:26: recipe for target 'memcheck' failed
make: *** [memcheck] Error 1

You can look at the backtrace and see which test is failing and the hint that address points to the zero page - Its likely a NULL deref

1 Like