[flashrom] [PATCH] CID1130005: Array compared against 0
Carl-Daniel Hailfinger
c-d.hailfinger.devel.2006 at gmx.net
Mon May 26 23:54:57 CEST 2014
Am 14.05.2014 00:05 schrieb Stefan Tauner:
> On Mon, 12 May 2014 10:32:32 +0200
> Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net> wrote:
>
>>> From: Stefan Tauner <stefan.tauner at alumni.tuwien.ac.at>
>>> Date: Fri, 9 May 2014 21:18:40 +0200
>>> Subject: [PATCH] Fix selfcheck of various arrays.
>>>
>>> Stefan Reinauer has reported ridiculous NULL checks for arrays in our
>>> self_check function found by Coverity (CID1130005). This patch removes
>>> the useless checks but keeps and fixes the one responsible for the
>>> flashchips array by exporting the array size in a new constant.
>>>
>>> Signed-off-by: Stefan Tauner <stefan.tauner at alumni.tuwien.ac.at>
>>> ---
>>> flash.h | 1 +
>>> flashchips.c | 4 +++-
>>> flashrom.c | 57 ++++++++++++++++++++++++---------------------------------
>>> 3 files changed, 28 insertions(+), 34 deletions(-)
>>>
>>> diff --git a/flash.h b/flash.h
>>> index 59f7cd4..4765213 100644
>>> --- a/flash.h
>>> +++ b/flash.h
>>> @@ -224,6 +224,7 @@ struct flashctx {
>>> #define TIMING_ZERO -2
>>>
>>> extern const struct flashchip flashchips[];
>>> +extern const unsigned int flashchips_size;
>>>
>>> void chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
>>> void chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr);
>>> diff --git a/flashchips.c b/flashchips.c
>>> index 8059374..92dc947 100644
>>> --- a/flashchips.c
>>> +++ b/flashchips.c
>>> @@ -13362,5 +13362,7 @@ const struct flashchip flashchips[] = {
>>> .write = NULL,
>>> },
>>>
>>> - { NULL }
>>> + {0}
>>> };
>>> +
>>> +const unsigned int flashchips_size = ARRAY_SIZE(flashchips);
>>> diff --git a/flashrom.c b/flashrom.c
>>> index c20461a..9d64da3 100644
>>> --- a/flashrom.c
>>> +++ b/flashrom.c
>>> @@ -1271,10 +1271,7 @@ out_free:
>>> return ret;
>>> }
>>>
>>> -/* This function shares a lot of its structure with erase_and_write_flash() and
>>> - * walk_eraseregions().
>>> - * Even if an error is found, the function will keep going and check the rest.
>>> - */
>>> +/* Even if an error is found, the function will keep going and check the rest. */
>> Not sure if we want to remove parts of the comment... if we ever change
>> the eraseblock structure or semantics, we may want to be able to quickly
>> locate all places where we have to change stuff. And that may happen
>> soon for some weird chips with erase commands which only happen to work
>> on parts of the chip. The idea some months ago was to mark eraseblocks
>> where the erase function doesn't work by design by using a negative
>> eraseblock size.
>> Hm.
> I'd definitely grep for the modified struct member(s) instead of some
> vague comments that might or might not exist :)
> The old comment reads to me as the author suggests that the similarity
> (which is not very surprising actually) should be exploited somehow
> (which I think would be a very bad idea). (erase_and_write_block_helper
> is already a nightmare that will probably never pay off - at least I
> can't see how that could happen).
OK with removing the comment.
>>> static int selfcheck_eraseblocks(const struct flashchip *chip)
>>> {
>>> int i, j, k;
>>> @@ -1697,8 +1694,7 @@ void print_banner(void)
>>>
>>> int selfcheck(void)
>>> {
>>> - const struct flashchip *chip;
>>> - int i;
>>> + unsigned int i;
>>> int ret = 0;
>>>
>>> /* Safety check. Instead of aborting after the first error, check
>>> @@ -1751,37 +1747,32 @@ int selfcheck(void)
>>> ret = 1;
>>> }
>>> }
>>> - /* It would be favorable if we could also check for correct termination
>>> - * of the following arrays, but we don't know their sizes in here...
>>> - * For 'flashchips' we check the first element to be non-null. In the
>>> - * other cases there exist use cases where the first element can be
>>> - * null. */
>>> - if (flashchips == NULL || flashchips[0].vendor == NULL) {
>>> +
>>> + /* It would be favorable if we could check for the correct layout (especially termination) of various
>>> + * constant arrays: flashchips, chipset_enables, board_matches, boards_known, laptops_known.
>>> + * They are all defined as externs in this compilation unit so we don't know their sizes which vary
>>> + * depending on compiler flags, e.g. the target architecture, and can sometimes be 0.
>>> + * For 'flashchips' we export the size explicitly to work around this and to be able to implement the
>>> + * checks below. */
>> IMHO the comment above is superfluous.
> Well, apparently quite a lot of people did not understand the problem
> that has been tried to be solved with the code following the original
> comment, neither was the code itself understood (else it would never
> have been committed), nor was the insanity of a completely bogus "fix"
> for this committed to chromiumos (after a review!) clear to the authors:
> https://chromium-review.googlesource.com/#/c/188240/
> To be fair, I did not notice the original problem myself either.
> All of the above indicates to me that there definitely should be an
> explanation, maybe not as verbose... feel free to suggest an
> alternative.
No alternative needed, your explanation is fine.
>>> + if (flashchips_size <= 1 || flashchips[flashchips_size-1].name != NULL) {
>> size == 1 is arguably stupid because no chip would be supported, but at
>> least programmer init will work and we can get some valuable info from
>> that as well. Not sure we want to forbid it. Then again, what use is
>> flashrom without any flash chip support? I tend to agree with the code
>> you propose.
> yes... *shrug*
>
>> Whitespace: flashchips_size - 1
> fixed.
>
>>> msg_gerr("Flashchips table miscompilation!\n");
>>> ret = 1;
>>> + } else {
>>> + for (i = 0; i < flashchips_size - 1; i++) {
>>> + const struct flashchip *chip = &flashchips[i];
>>> + if (chip->vendor == NULL || chip->name == NULL || chip->bustype == BUS_NONE) {
>>> + ret = 1;
>>> + msg_gerr("ERROR: Some field of flash chip #%d (%s) is misconfigured.\n"
>>> + "Please report a bug at flashrom at flashrom.org\n", i,
>>> + chip->name == NULL ? "unnamed" : chip->name);
>>> + }
>>> + if (selfcheck_eraseblocks(chip)) {
>>> + ret = 1;
>>> + }
>>> + }
>>> }
>>> - for (chip = flashchips; chip && chip->name; chip++)
>>> - if (selfcheck_eraseblocks(chip))
>>> - ret = 1;
>>>
>>> -#if CONFIG_INTERNAL == 1
>>> - if (chipset_enables == NULL) {
>>> - msg_gerr("Chipset enables table does not exist!\n");
>>> - ret = 1;
>>> - }
>>> - if (board_matches == NULL) {
>>> - msg_gerr("Board enables table does not exist!\n");
>>> - ret = 1;
>>> - }
>>> - if (boards_known == NULL) {
>>> - msg_gerr("Known boards table does not exist!\n");
>>> - ret = 1;
>>> - }
>>> - if (laptops_known == NULL) {
>>> - msg_gerr("Known laptops table does not exist!\n");
>>> - ret = 1;
>>> - }
>>> -#endif
>> Please leave out that removal or replace it with similar size checks as
>> for flashchips[] except that the other array sizes only fail if <1. The
>> way you do the checks above is definitely the way to go.
> Why should I keep useless and embarrassing code in when the comment
> below replaces it well?
Yes, given that you added the FIXME comment above, a removal here is OK.
> And BTW i don't deem the other arrays worth
> checking. The flashchips array is special because it is complicated and
> the complexity (i.e. eraser layouts) can easily be checked for sanity
> automatically. The others are simply arrays with easily to check
> semantics and syntaxes.
Except the board enable table which is a nightmare on its own, and even
I don't remember the exact semantics for which fields are required in
which combination for which effect unless I explicitly read the code and
comments.
That said, given funnies like arch-specific contents of some arrays
(e.g. processor enables, chipset enables), I'd like to have some checks
for them as well just to make sure compilation on non-x86 doesn't mess
them up. This can be done in a followup patch, though.
> If I'd touch related code at all then I would
> like to remove the NULL delimiter and use the (then exported) constant
> size variables to iterate over them everywhere.
Hm. I wonder if that causes any fun down the road when someone changes a
checked array and recompiles only the affected file. Should be safe.
Anyway, having a NULL-containing member as terminator allows us to
iterate over pointers instead of having to use an explicit counter
variable somewhere.
>>> + /* TODO: implement similar sanity checks for other arrays where deemed necessary. */
>>> return ret;
>>> }
>>>
> Sorry for being a bit bitchy today :)
Sorry for the long delay of approval.
Regards,
Carl-Daniel
--
http://www.hailfinger.org/
More information about the flashrom
mailing list