1

I wrote a simple C program to demonstrate the checksum error detection technique in computer networks. To do this, I used the char datatype in C, #define'd it to byte and ran the code. For some reason, I'm getting a weird bug where the corrupted byte is being printed such that it has a difference of "FFFFFF80" with the original byte.

This is the code that I'm running:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>

#define byte char
#define MAX_STRING 0xFFFF
#define BYTE_SIZE 8

#define min(a, b) a < b ? a : b

byte *corrupt_string(byte *string, int length, int bits);
void print_string(byte *string, int length);
byte *copy_string(byte *string, int length);
char *make_string(char ch, int repetition);
void debug_corruption(byte *target, byte *source, int length);
bool is_corrupt(byte *target, byte *source, int length);


int main(int argc, char **argv)
{
    byte *input, *corrupted;
    int input_length;

    if (argc != 2)
    {
        printf("Usage: <bin> \"<data string>\"");
        return EXIT_FAILURE;
    }

    srand(time(NULL));

    input = argv[1];
    input_length = strnlen_s(input, MAX_STRING);

    corrupted = corrupt_string(copy_string(input, input_length),
                               input_length, 1);

    debug_corruption(corrupted, input, input_length);

    printf("\n%s\nResult\t\t\t: ", make_string('-', 0x80));
    if (is_corrupt(input, corrupted, input_length))
        printf("String is corrupted\n");
    else
        printf("String is not corrupted\n");
    return EXIT_SUCCESS;
}

byte *corrupt_string(byte *string, int length, int bits)
{
    int i;

    for (i = 0; i < bits; i++)
    {
        int index = rand() % length;
        int bit_pos = rand() % BYTE_SIZE;

        if (rand() % 2 == 0)
        {
            continue;
        }

        string[index] ^= ((byte)1 << bit_pos);
    }
    return string;
}

void print_string(byte *string, int length)
{
    int i, i_max = min(length, MAX_STRING) - 1;

    for (i = 0;; i++)
    {
        if (string[i] == 0)
            printf("..");
        else
            printf("%02X", string[i]);

        if (i == i_max)
            return;
        printf(" ");
    }
}

byte *copy_string(byte *string, int length)
{
    byte *result = (byte *)calloc(length, sizeof(byte));

    memcpy_s(result, length, string, length);
    return result;
}

char *make_string(char ch, int repetition)
{
    char *result;

    if (repetition <= 0)
    {
        return "";
    }
    result = (char *)calloc(repetition + 1, sizeof (char));
    memset(result, ch, repetition * sizeof (char));

    result[repetition] = 0;
    return result;
}

void debug_corruption(byte *target, byte *source, int length)
{
    int i;
    byte *diff_string;
    
    printf("Before corruption\t: ");
    print_string(source, length);

    printf("\n\nAfter corruption\t: ");
    print_string(target, length);

    diff_string = (byte *)calloc(length, sizeof(byte));
    for (i = 0; i < length; i++)
    {
        byte diff = (byte)abs(source[i] - target[i]);
        diff_string[i] = diff;
    }

    printf("\n%s\nCorrupted parts\t\t: ", make_string('-', 0x80));
    print_string(diff_string, length);
    printf("\n");
}

bool is_corrupt(byte *target, byte *source, int length)
{
    byte check_sum1 = (byte)0, check_sum2;

    for (int i = 0; i < length; i++)
    {
        check_sum1 += source[i];
    }
    check_sum1 = -check_sum1;

    check_sum2 = check_sum1;
    for (int i = 0; i < length; i++)
    {
        check_sum2 += target[i];
    }

    return (check_sum2 != 0);
}

And here's some outputs that got the error(including the command line arguments): https://pastebin.com/mwQjZ1yD

Thorfinn
  • 43
  • 5
  • 4
    Change your definition of `byte` to `unsigned char` and see what happens. – Eugene Sh. Mar 23 '23 at 15:12
  • 2
    Also your `min` macro is strictly following the guidelines of how *not* to write macros. Think what `min(length, MAX_STRING) - 1` is expanding into. Read [this](https://stuff.mit.edu/afs/athena/project/rhel-doc/3/rhel-cpp-en-3/macro-pitfalls.html) for example – Eugene Sh. Mar 23 '23 at 15:14
  • 2
    [Is char signed or unsigned by default?](https://stackoverflow.com/questions/2054939/is-char-signed-or-unsigned-by-default) You should neither use `char` nor your own private garage standard. Use `uint8_t` from `stdint.h`. – Lundin Mar 23 '23 at 15:22
  • Thorfinn, Also `copy_string()` fails to account for the _null character_. – chux - Reinstate Monica Mar 23 '23 at 17:00
  • @EugeneSh. you're correct. I seem to have this bad habit of not parenthesizing macro definitions – Thorfinn Mar 24 '23 at 09:01
  • @Lundin changing to unit8_t and doing a bit of explicit type-casting to pass to and from string methods, did the trick. Thanks! – Thorfinn Mar 24 '23 at 10:35

0 Answers0