Fundamentals 5 min read

Boundary Value Bugs in Software Testing: Three Typical Cases and Their Fixes

The article reviews three common boundary‑value bugs encountered during software testing, explains why they occur, shows the original C code that triggers each issue, and provides concise corrections to prevent off‑by‑one errors and buffer overflows.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Boundary Value Bugs in Software Testing: Three Typical Cases and Their Fixes

Long‑term testing experience shows that most errors happen at the edges of input or output ranges rather than inside them. This second article in a series presents three typical boundary‑value bugs, their root causes, and simple fixes.

Bug 1 – Buffer Size Check

Bug description: When checking whether a destination buffer can hold a formatted string, the condition fails to account for the terminating null character, causing the last character to be dropped when sprintf writes the data.

if((size_t)dest_size < strlen(idc) + strlen(host) + strlen(tmp))
{
    LOG_ERR("%s failed. Dest buffer_size is not enough.",_func_);
    return ERR_BUF_NOT_ENOUGH;
}

The code intends to reject insufficient space, but because the null terminator is ignored, a buffer that is exactly the needed size is considered sufficient, leading to truncation.

Solution: Change the comparison to <= so the null byte is counted.

Bug 2 – Retry Counter Off‑by‑One

Bug description: When sending a message, the retry loop increments try_send_times after the check, causing the actual number of attempts to exceed the configured maximum by one.

if (status == -1)
{
    // send message failed
    if (errno == EAGAIN)
    {
        if (try_send_times < MAX_SEND_MSG_TIMES)
        {
            LOG_WARN("msg queue is full! try_send_times:%d",try_send_times);
            usleep(5000);
            try_send_times++;
            continue;
        }
        else
        {
            LOG_ERR("msg queue is full! try send message times are larger than MAX TIMES: %d",MAX_SEND_MSG_TIMES);
        }
    }
    else
    {
        LOG_ERR("Send msg failed! Err: %s", strerror(errno));
    }
}

The loop exits after the condition fails, but the counter has already been incremented, resulting in MAX_SEND_MSG_TIMES + 1 attempts.

Solution: Initialise try_send_times to 1 (or adjust the logic so the increment happens only after a successful retry).

Bug 3 – Increment Inside Condition

Bug description: Using a post‑increment operator in the condition ( if(try_get_times++ < _max_repeat_read_times) ) makes the counter increase even when the condition is false, so the final logged count is one higher than the actual limit.

if(try_get_times++ < _max_repeat_read_times)
{
    ...
}
...
if (try_get_times >= _max_repeat_read_times)
{
    LOG_ERR("%s: Error value of key: %s, Execute %d times", __func__,key, try_get_times);
}

Each evaluation increments try_get_times , so after the loop the logged value becomes _max_repeat_read_times + 1 .

Solution: Move the increment inside the if block or log _max_repeat_read_times instead of the incremented variable.

Conclusion

These examples illustrate that boundary‑value problems often hide in seemingly trivial checks or loop conditions. Testers should examine not only the explicit conditions but also the surrounding logic, and apply defensive coding practices to avoid off‑by‑one and buffer‑size errors.

software testingC programmingbug-fixingboundary testingdefensive codingoff‑by‑one errors
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.