1: Sample code that reproduces the problem.
_Optional int *poi;
void chandler(_Optional int **ppoi)
{
int i;
// constrains poi to non-null on the fallthrough path
if (!poi) return;
*poi = 1; // no recommended diagnostic
*ppoi = &i; // non-null constraint on poi is unaffected
*poi = 2; // no recommended diagnostic
}
void monica(_Optional int **ppoi, _Optional int *lpoi)
{
// constrains poi and lpoi to non-null on the fallthrough path
if (!poi || !lpoi) return;
*poi = 1; // no recommended diagnostic
*ppoi = lpoi; // non-null constraint on poi is unaffected
*poi = 2; // no recommended diagnostic
}
void rachel(_Optional int **ppoi_1, _Optional int **ppoi_2)
{
int i;
// constrains *ppoi_1 to non-null on the fallthrough path
if (!*ppoi_1) return;
**ppoi_1 = 1; // no recommended diagnostic
*ppoi_2 = &i; // non-null constraint on *ppoi_1 is unaffected
**ppoi_1 = 2; // no recommended diagnostic
}
2: Exact command used to run SDCC on this sample code
sdcc --std=c23 -c /work/bug6.c
3: SDCC version tested (type "sdcc -v" to find it)
SDCC : mcs51/z80/z180/r2k/r2ka/r3ka/r4k/r5k/r6k/sm83/tlcs90/ez80/z80n/r800/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15/mos6502/mos65c02/f8/f8l TD- 4.5.21 #16327 (Linux)
4: Copy of the error message or incorrect output, or a clear description of the observed versus expected behavior.
The above examples from the Recommended Practice part of subsection 6.5.2 "Type qualifiers" in the _Optional TS are intended to illustrate best-case analysis that might be possible if a translator takes into account whether the value assigned to a pointer (that could alias another pointer) can be null, and therefore whether it is necessary to discard previously-inferred constraints on the value of other pointers that the analyser is tracking.
In chandler, the value of poi, an object declared at file scope that points to an optional-qualified type, is constrained to be non-null on the fallthrough path of an if statement, therefore the implementation is recommended not to produce a diagnostic message for the lvalue *poi in the first assignment. ppoi, a pointer to a pointer to an optional-qualified type, cannot be proven not to point to poi without interprocedural analysis. The assignment of &i to the lvalue *ppoi can modify the value of poi, but the assigned value is not a null pointer. The implementation is therefore recommended not to produce a diagnostic message for the lvalue *poi in the last assignment.
The monica function is similar to chandler except that the assigned value can be proven by flow-sensitive analysis to be non-null, as opposed to its non-null value being a known compile-time constant.
The rachel function is similar to chandler except that the address of the potentially-aliased pointer is passed as an argument instead of the potentially-aliased pointer being a global variable.
SDCC produces diagnostic messages for the final assignment in each function:
/work/bug6.c:12: warning 355: pointer to _Optional could not be proven to be non-null at dereference
/work/bug6.c:22: warning 355: pointer to _Optional could not be proven to be non-null at dereference
/work/bug6.c:34: warning 355: pointer to _Optional could not be proven to be non-null at dereference
Ideally, no diagnostic messages would be produced for these examples.
This is not a bug because it concerns Recommended Practice. I thought it might be useful to report it regardless, in case there is scope for improvement (if the maintainers of SDCC consider that useful).
Bugs: #4148
Bugs: #4167
Feature Requests: #1032
Wiki: SDCC 4.7.0 Release
As of current SDCC trunk, since the recent merge of the
_Optionalbranch, we only get the warning in line 34.Confirmed that only the warning at line 34 appears now. Great progress.
I am attaching a proposed bugfix for this issue, created with assistance from Codex. I hope that it will prove acceptable when reviewed by SDCC's maintainers.
I did the following testing of the proposed patch:
i.e.
make -j2
make -C support/regression clean-results
make -C support/regression -j2 test-ucz80
make -C support/valdiag clean
make -C support/valdiag -j2
Summary for 'ucz80': 0 failures, 36740 tests, 6407 test cases, 7347620 bytes, 1613638336 ticks
Summary for 'mcs51': 0 failures, 652 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'mcs51-large': 0 failures, 650 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'mcs51-stack-auto': 0 failures, 651 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'ds390': 0 failures, 638 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'z80': 0 failures, 641 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'z180': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'r2k': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'r4k': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'sm83': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'tlcs90': 0 failures, 640 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 's08': 0 failures, 639 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'mos6502': 0 failures, 639 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'f8': 0 failures, 638 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'pdk13': 0 failures, 641 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'pdk14': 0 failures, 639 tests, 373 test cases, 0 bytes, 0 ticks
Summary for 'pdk15': 0 failures, 637 tests, 373 test cases, 0 bytes, 0 ticks