Skip to content
C Basics: Reject Oversized Lines Without Losing the Next Record

C Basics: Reject Oversized Lines Without Losing the Next Record

November 1, 2026

A truncated read is not necessarily a complete line. Apply a seven-byte record limit and discard an oversized record without interpreting its remainder as another record.

Prepare a scratch directory

Tested on Linux x86-64 with GCC 14.2.0. You need GCC, the C development headers, Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. This example uses the C standard library and no external package.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1

Run the example

Save this as fgets-line-boundaries-demo.c:

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

int main(void) {
    char line[8];
    while (fgets(line, sizeof line, stdin) != NULL) {
        char *newline = strchr(line, '\n');
        if (newline != NULL) {
            *newline = '\0';
        } else {
            int next_character = fgetc(stdin);
            if (next_character != '\n' && next_character != EOF) {
                do {
                    next_character = fgetc(stdin);
                } while (next_character != '\n' && next_character != EOF);
                if (ferror(stdin)) {
                    fputs("Input failed\n", stderr);
                    return EXIT_FAILURE;
                }
                puts("Rejected: line exceeds seven bytes");
                continue;
            }
            if (ferror(stdin)) {
                fputs("Input failed\n", stderr);
                return EXIT_FAILURE;
            }
        }
        printf("Accepted: [%s]\n", line);
    }
    if (ferror(stdin)) {
        fputs("Input failed\n", stderr);
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Compile and run it. The && prevents running an old executable if compilation fails:

gcc -std=c17 -Wall -Wextra -Werror -pedantic fgets-line-boundaries-demo.c -o fgets-line-boundaries-demo &&
printf 'short\n1234567\n12345678\nnext\nfinal' | ./fgets-line-boundaries-demo

Observed output:

Accepted: [short]
Accepted: [1234567]
Rejected: line exceeds seven bytes
Accepted: [next]
Accepted: [final]

Read the result

fgets reserves one byte for the null terminator. A missing newline can mean a full buffer or a final line without a newline. Looking at one more character distinguishes a seven-byte line followed by newline or EOF from an oversized line. Draining the remainder keeps the next read aligned.

Apply it carefully

This is a bounded, newline-delimited, NUL-free text example. It counts bytes, not Unicode characters, and does not accept embedded null bytes or normalize CRLF. For arbitrary binary input, track explicit lengths instead of using strchr. Draining a long live stream can block until a delimiter or EOF; network protocols also need time and total-input limits.

The library reference describes the relevant behavior.

Clean up

Remove only the source and executable created here, then remove the empty scratch directory:

rm -- fgets-line-boundaries-demo.c fgets-line-boundaries-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directory

If the directory is not empty, inspect what remains before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on