Fixes for issues found by GCC analyzer.
This commit is contained in:
parent
d9889b2fbb
commit
36c6eeaf81
12 changed files with 270 additions and 100 deletions
54
analyze.sh
Executable file
54
analyze.sh
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# analyze.sh -- run the DJGPP build under gcc's -fanalyzer.
|
||||
#
|
||||
# Usage:
|
||||
# ./analyze.sh # analyse the whole build (slow: 2-5x)
|
||||
# ./analyze.sh 2>&1 | tee analyze.log
|
||||
#
|
||||
# How it works:
|
||||
#
|
||||
# The project Makefiles hardcode -Werror in CFLAGS. gcc evaluates
|
||||
# diagnostic flags in order, so a trailing -Wno-error (appended
|
||||
# AFTER CFLAGS at compile time) demotes analyzer findings back to
|
||||
# warnings -- otherwise the first analyzer hit aborts the build.
|
||||
#
|
||||
# We do that by setting CC to a wrapper that execs the real compiler
|
||||
# with -fanalyzer prepended and -Wno-error appended. make -k keeps
|
||||
# building after individual failures so we see every hit in one run.
|
||||
#
|
||||
# Runs the existing top-level Makefile with an override CC; no
|
||||
# Makefile edits required. Output goes to stderr; redirect with
|
||||
# '2>&1 | tee analyze.log' to capture.
|
||||
|
||||
set -u
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
REAL_CC="$HOME/djgpp/djgpp/bin/i586-pc-msdosdjgpp-gcc"
|
||||
|
||||
if [ ! -x "$REAL_CC" ]; then
|
||||
echo "analyze.sh: $REAL_CC not executable" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build the wrapper in a temp dir that the spawned makes can see.
|
||||
WRAP_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$WRAP_DIR"' EXIT
|
||||
WRAP="$WRAP_DIR/analyze-cc"
|
||||
|
||||
cat > "$WRAP" <<WRAPEOF
|
||||
#!/bin/bash
|
||||
exec "$REAL_CC" -fanalyzer "\$@" -Wno-error
|
||||
WRAPEOF
|
||||
|
||||
chmod +x "$WRAP"
|
||||
|
||||
echo "analyze.sh: running full build under gcc -fanalyzer..." >&2
|
||||
echo "analyze.sh: this will be slow (2-5x normal build time)." >&2
|
||||
|
||||
# -k = keep going after errors so we collect every analyzer hit
|
||||
# CC=... overrides the assignment in each submakefile
|
||||
make -k CC="$WRAP" 2>&1
|
||||
|
||||
echo "analyze.sh: done. Grep for 'Wanalyzer' to see findings." >&2
|
||||
|
|
@ -142,6 +142,12 @@ void widgetDestroyChildren(WidgetT *w);
|
|||
// Allocation
|
||||
WidgetT *widgetAlloc(WidgetT *parent, int32_t type);
|
||||
|
||||
// Undo a successful widgetAlloc when a subsequent data-struct
|
||||
// allocation fails. Detaches from parent, removes from the poll
|
||||
// list, frees the widget struct. Call only before w->data has
|
||||
// been set; once data is attached, use wgtDestroy instead.
|
||||
void widgetAllocRollback(WidgetT *w);
|
||||
|
||||
// Allocate a widget of the given type PLUS a data struct of dataSize
|
||||
// bytes. The data struct must begin with a `const char *text` field
|
||||
// (WCLASS_HAS_TEXT semantics); this field is set to strdup(text) and
|
||||
|
|
|
|||
|
|
@ -257,6 +257,34 @@ WidgetT *widgetAlloc(WidgetT *parent, int32_t type) {
|
|||
}
|
||||
|
||||
|
||||
// Undo a successful widgetAlloc for a widget whose data-struct
|
||||
// allocation subsequently failed. Detaches from parent, removes
|
||||
// from the poll list, and frees the widget struct. Safe only
|
||||
// before w->data has been set -- once data is attached, use
|
||||
// wgtDestroy to run the widget's full teardown path.
|
||||
void widgetAllocRollback(WidgetT *w) {
|
||||
if (!w) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (w->parent) {
|
||||
widgetRemoveChild(w->parent, w);
|
||||
}
|
||||
|
||||
if (w->wclass && (w->wclass->flags & WCLASS_NEEDS_POLL)) {
|
||||
for (int32_t i = 0; i < sPollWidgetCount; i++) {
|
||||
if (sPollWidgets[i] == w) {
|
||||
arrdel(sPollWidgets, i);
|
||||
sPollWidgetCount = (int32_t)arrlen(sPollWidgets);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(w);
|
||||
}
|
||||
|
||||
|
||||
WidgetT *widgetAllocWithText(WidgetT *parent, int32_t type, size_t dataSize, const char *text) {
|
||||
WidgetT *w = widgetAlloc(parent, type);
|
||||
|
||||
|
|
@ -267,11 +295,9 @@ WidgetT *widgetAllocWithText(WidgetT *parent, int32_t type, size_t dataSize, con
|
|||
void *data = calloc(1, dataSize);
|
||||
|
||||
if (!data) {
|
||||
// Widget itself is already in the tree; leave it rather than
|
||||
// attempting a partial rollback (widget destroy is idempotent
|
||||
// via the parent teardown).
|
||||
dvxLog("Widget: failed to allocate %u-byte data for type %d", (unsigned)dataSize, type);
|
||||
return w;
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The data struct must begin with a `const char *text` field.
|
||||
|
|
|
|||
|
|
@ -355,26 +355,32 @@ WidgetT *wgtCanvas(WidgetT *parent, int32_t w, int32_t h) {
|
|||
|
||||
WidgetT *wgt = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (wgt) {
|
||||
wgt->contentOffX = CANVAS_BORDER;
|
||||
wgt->contentOffY = CANVAS_BORDER;
|
||||
|
||||
CanvasDataT *cd = (CanvasDataT *)calloc(1, sizeof(CanvasDataT));
|
||||
|
||||
cd->pixelData = data;
|
||||
cd->canvasW = w;
|
||||
cd->canvasH = h;
|
||||
cd->canvasPitch = pitch;
|
||||
cd->canvasBpp = bpp;
|
||||
cd->penColor = packColor(d, 0, 0, 0);
|
||||
cd->penSize = 1;
|
||||
cd->lastX = -1;
|
||||
cd->lastY = -1;
|
||||
wgt->data = cd;
|
||||
} else {
|
||||
if (!wgt) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wgt->contentOffX = CANVAS_BORDER;
|
||||
wgt->contentOffY = CANVAS_BORDER;
|
||||
|
||||
CanvasDataT *cd = (CanvasDataT *)calloc(1, sizeof(CanvasDataT));
|
||||
|
||||
if (!cd) {
|
||||
free(data);
|
||||
widgetAllocRollback(wgt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cd->pixelData = data;
|
||||
cd->canvasW = w;
|
||||
cd->canvasH = h;
|
||||
cd->canvasPitch = pitch;
|
||||
cd->canvasBpp = bpp;
|
||||
cd->penColor = packColor(d, 0, 0, 0);
|
||||
cd->penSize = 1;
|
||||
cd->lastX = -1;
|
||||
cd->lastY = -1;
|
||||
wgt->data = cd;
|
||||
return wgt;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,16 +81,23 @@ void widgetImagePaint(WidgetT *w, DisplayT *disp, const BlitOpsT *ops, const Bit
|
|||
WidgetT *wgtImage(WidgetT *parent, uint8_t *pixelData, int32_t w, int32_t h, int32_t pitch) {
|
||||
WidgetT *wgt = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (wgt) {
|
||||
ImageDataT *d = calloc(1, sizeof(ImageDataT));
|
||||
d->pixelData = pixelData;
|
||||
d->imgW = w;
|
||||
d->imgH = h;
|
||||
d->imgPitch = pitch;
|
||||
d->pressed = false;
|
||||
wgt->data = d;
|
||||
if (!wgt) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ImageDataT *d = calloc(1, sizeof(ImageDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(wgt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->pixelData = pixelData;
|
||||
d->imgW = w;
|
||||
d->imgH = h;
|
||||
d->imgPitch = pitch;
|
||||
d->pressed = false;
|
||||
wgt->data = d;
|
||||
return wgt;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,17 +81,25 @@ WidgetT *wgtImageButton(WidgetT *parent, uint8_t *pixelData, int32_t w, int32_t
|
|||
|
||||
WidgetT *wgt = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (wgt) {
|
||||
ImageButtonDataT *d = calloc(1, sizeof(ImageButtonDataT));
|
||||
d->pixelData = pixelData;
|
||||
d->imgW = w;
|
||||
d->imgH = h;
|
||||
d->imgPitch = pitch;
|
||||
wgt->data = d;
|
||||
} else {
|
||||
if (!wgt) {
|
||||
free(pixelData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ImageButtonDataT *d = calloc(1, sizeof(ImageButtonDataT));
|
||||
|
||||
if (!d) {
|
||||
free(pixelData);
|
||||
widgetAllocRollback(wgt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->pixelData = pixelData;
|
||||
d->imgW = w;
|
||||
d->imgH = h;
|
||||
d->imgPitch = pitch;
|
||||
wgt->data = d;
|
||||
|
||||
return wgt;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,14 +68,21 @@ void widgetProgressBarPaint(WidgetT *w, DisplayT *disp, const BlitOpsT *ops,
|
|||
WidgetT *wgtProgressBar(WidgetT *parent) {
|
||||
WidgetT *w = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (w) {
|
||||
ProgressBarDataT *d = calloc(1, sizeof(ProgressBarDataT));
|
||||
d->value = 0;
|
||||
d->maxValue = 100;
|
||||
d->vertical = false;
|
||||
w->data = d;
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ProgressBarDataT *d = calloc(1, sizeof(ProgressBarDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->value = 0;
|
||||
d->maxValue = 100;
|
||||
d->vertical = false;
|
||||
w->data = d;
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
@ -108,14 +115,21 @@ void wgtProgressBarSetValue(WidgetT *w, int32_t value) {
|
|||
WidgetT *wgtProgressBarV(WidgetT *parent) {
|
||||
WidgetT *w = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (w) {
|
||||
ProgressBarDataT *d = calloc(1, sizeof(ProgressBarDataT));
|
||||
d->value = 0;
|
||||
d->maxValue = 100;
|
||||
d->vertical = true;
|
||||
w->data = d;
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ProgressBarDataT *d = calloc(1, sizeof(ProgressBarDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->value = 0;
|
||||
d->maxValue = 100;
|
||||
d->vertical = true;
|
||||
w->data = d;
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,20 +65,27 @@ void widgetSeparatorPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops,
|
|||
WidgetT *wgtHSeparator(WidgetT *parent) {
|
||||
WidgetT *w = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (w) {
|
||||
SeparatorDataT *d = calloc(1, sizeof(SeparatorDataT));
|
||||
// Auto-orient to the parent: horizontal container -> vertical
|
||||
// divider, vertical container -> horizontal divider. This
|
||||
// lets a single "Line" basName work correctly in both
|
||||
// toolbars and menus without requiring callers to pick
|
||||
// between HSeparator and VSeparator by widget type.
|
||||
if (parent && widgetIsHorizContainer(parent->type)) {
|
||||
d->vertical = true;
|
||||
}
|
||||
|
||||
w->data = d;
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SeparatorDataT *d = calloc(1, sizeof(SeparatorDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Auto-orient to the parent: horizontal container -> vertical
|
||||
// divider, vertical container -> horizontal divider. This
|
||||
// lets a single "Line" basName work correctly in both
|
||||
// toolbars and menus without requiring callers to pick
|
||||
// between HSeparator and VSeparator by widget type.
|
||||
if (parent && widgetIsHorizContainer(parent->type)) {
|
||||
d->vertical = true;
|
||||
}
|
||||
|
||||
w->data = d;
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
@ -126,12 +133,19 @@ void wgtRegister(void) {
|
|||
WidgetT *wgtVSeparator(WidgetT *parent) {
|
||||
WidgetT *w = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (w) {
|
||||
SeparatorDataT *d = calloc(1, sizeof(SeparatorDataT));
|
||||
w->data = d;
|
||||
d->vertical = true;
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SeparatorDataT *d = calloc(1, sizeof(SeparatorDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
w->data = d;
|
||||
d->vertical = true;
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,15 +132,22 @@ void wgtRegister(void) {
|
|||
WidgetT *wgtSlider(WidgetT *parent, int32_t minVal, int32_t maxVal) {
|
||||
WidgetT *w = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (w) {
|
||||
SliderDataT *d = (SliderDataT *)calloc(1, sizeof(SliderDataT));
|
||||
d->value = minVal;
|
||||
d->minValue = minVal;
|
||||
d->maxValue = maxVal;
|
||||
w->data = d;
|
||||
w->weight = WGT_WEIGHT_FILL;
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SliderDataT *d = (SliderDataT *)calloc(1, sizeof(SliderDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->value = minVal;
|
||||
d->minValue = minVal;
|
||||
d->maxValue = maxVal;
|
||||
w->data = d;
|
||||
w->weight = WGT_WEIGHT_FILL;
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,14 +170,21 @@ void wgtRegister(void) {
|
|||
WidgetT *wgtSplitter(WidgetT *parent, bool vertical) {
|
||||
WidgetT *w = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (w) {
|
||||
SplitterDataT *d = (SplitterDataT *)calloc(1, sizeof(SplitterDataT));
|
||||
d->vertical = vertical;
|
||||
d->dividerPos = 0;
|
||||
w->data = d;
|
||||
w->weight = WGT_WEIGHT_FILL;
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SplitterDataT *d = (SplitterDataT *)calloc(1, sizeof(SplitterDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->vertical = vertical;
|
||||
d->dividerPos = 0;
|
||||
w->data = d;
|
||||
w->weight = WGT_WEIGHT_FILL;
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -193,14 +193,21 @@ static bool tabNeedScroll(const WidgetT *w, const BitmapFontT *font) {
|
|||
WidgetT *wgtTabControl(WidgetT *parent) {
|
||||
WidgetT *w = widgetAlloc(parent, sTabControlTypeId);
|
||||
|
||||
if (w) {
|
||||
TabControlDataT *d = calloc(1, sizeof(TabControlDataT));
|
||||
d->activeTab = 0;
|
||||
d->scrollOffset = 0;
|
||||
w->data = d;
|
||||
w->weight = WGT_WEIGHT_FILL;
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TabControlDataT *d = calloc(1, sizeof(TabControlDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->activeTab = 0;
|
||||
d->scrollOffset = 0;
|
||||
w->data = d;
|
||||
w->weight = WGT_WEIGHT_FILL;
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
@ -225,13 +232,20 @@ void wgtTabControlSetActive(WidgetT *w, int32_t idx) {
|
|||
WidgetT *wgtTabPage(WidgetT *parent, const char *title) {
|
||||
WidgetT *w = widgetAlloc(parent, sTabPageTypeId);
|
||||
|
||||
if (w) {
|
||||
TabPageDataT *d = calloc(1, sizeof(TabPageDataT));
|
||||
d->title = strdup(title ? title : "");
|
||||
w->data = d;
|
||||
w->accelKey = accelParse(d->title);
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TabPageDataT *d = calloc(1, sizeof(TabPageDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d->title = strdup(title ? title : "");
|
||||
w->data = d;
|
||||
w->accelKey = accelParse(d->title);
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,19 +101,26 @@ static void widgetTimerDestroy(WidgetT *w) {
|
|||
WidgetT *wgtTimer(WidgetT *parent, int32_t intervalMs, bool repeat) {
|
||||
WidgetT *w = widgetAlloc(parent, sTypeId);
|
||||
|
||||
if (w) {
|
||||
TimerDataT *d = calloc(1, sizeof(TimerDataT));
|
||||
w->data = d;
|
||||
w->visible = false;
|
||||
d->intervalMs = intervalMs;
|
||||
d->repeat = repeat;
|
||||
// Match VB Timer default (Enabled=True on create). Callers can
|
||||
// Stop() if they want it dormant.
|
||||
d->running = true;
|
||||
d->lastFire = clock();
|
||||
timerAddToActiveList(w);
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TimerDataT *d = calloc(1, sizeof(TimerDataT));
|
||||
|
||||
if (!d) {
|
||||
widgetAllocRollback(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
w->data = d;
|
||||
w->visible = false;
|
||||
d->intervalMs = intervalMs;
|
||||
d->repeat = repeat;
|
||||
// Match VB Timer default (Enabled=True on create). Callers can
|
||||
// Stop() if they want it dormant.
|
||||
d->running = true;
|
||||
d->lastFire = clock();
|
||||
timerAddToActiveList(w);
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue