
…ring.UninitRead This is a drastic simplification of #106982. If you read that patch, this is the same thing with all BugReporterVisitors.cpp and SValBuilder.cpp changes removed! (since all replies came regarding changed to those files, I felt the new PR was justified) The patch was inspired by a pretty poor bug report on FFMpeg:  In this bug report, block is uninitialized, hence the bug report that it should not have been passed to memcpy. The confusing part is in line 93, where block was passed as a non-const pointer to seq_unpack_rle_block, which was obviously meant to initialize block. As developers, we know that clang likely didn't skip this function and found a path of execution on which this initialization failed, but NoStoreFuncVisitor failed to attach the usual "returning without writing to block" message. I fixed this by instead of tracking the entire array, I tracked the actual element which was found to be uninitialized (Remember, we heuristically only check if the first and last-to-access element is initialized, not the entire array). This is how the bug report looks now, with 'seq_unpack_rle_block' having notes describing the path of execution and lack of a value change:   Since NoStoreFuncVisitor was a TU-local class, I moved it back to BugReporterVisitors.h, and registered it manually in CStringChecker.cpp. This was done because we don't have a good trackRegionValue() function, only a trackExpressionValue() function. We have an expression for the array, but not for its first (or last-to-access) element, so I only had a MemRegion on hand.
26 lines
1.2 KiB
C
26 lines
1.2 KiB
C
// RUN: %clang_analyze_cc1 -verify %s \
|
|
// RUN: -analyzer-checker=core,alpha.unix.cstring \
|
|
// RUN: -analyzer-output=text
|
|
|
|
#include "Inputs/system-header-simulator.h"
|
|
|
|
// Inspired by a report on ffmpeg, libavcodec/tiertexseqv.c, seq_decode_op1().
|
|
int coin();
|
|
|
|
void maybeWrite(const char *src, unsigned size, int *dst) {
|
|
if (coin()) // expected-note{{Assuming the condition is false}}
|
|
// expected-note@-1{{Taking false branch}}
|
|
memcpy(dst, src, size);
|
|
} // expected-note{{Returning without writing to '*dst'}}
|
|
|
|
void returning_without_writing_to_memcpy(const char *src, unsigned size) {
|
|
int block[8 * 8]; // expected-note{{'block' initialized here}}
|
|
// expected-note@+1{{Calling 'maybeWrite'}}
|
|
maybeWrite(src, size, block); // expected-note{{Returning from 'maybeWrite'}}
|
|
|
|
int buf[8 * 8];
|
|
memcpy(buf, &block[0], 8); // expected-warning{{The first element of the 2nd argument is undefined [alpha.unix.cstring.UninitializedRead]}}
|
|
// expected-note@-1{{The first element of the 2nd argument is undefined}}
|
|
// expected-note@-2{{Other elements might also be undefined}}
|
|
}
|