With LLVM 10.0.0+, the following codes in fdt_num_mem_rsv() does not work any more for an fdt that is at address 0: for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { if (fdt64_ld_(&re->size) == 0) return i; } Due to LLVM's optimization engine utilizing a UB in C, the following code pattern: if ((pointer + offset) != NULL) is transformed into: if (pointer != NULL) because if pointer is NULL and offset is non-zero, the result of (pointer + offset) is UB. So LLVM is free to exploit such UB to perform some optimization. In this case, fdt_mem_rsv() gets inlined and returns (pointer + offset). And LLVM in turns emits codes to check fdt against NULL, which won't work for fdt at address 0. Signed-off-by: Bin Meng <bmeng.cn@xxxxxxxxx> --- libfdt/fdt_ro.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 17584da..4db4013 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -157,18 +157,26 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle) return 0; } -static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) +static bool fdt_is_mem_rsv(const void *fdt, int n) { unsigned int offset = n * sizeof(struct fdt_reserve_entry); unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset; if (!can_assume(VALID_INPUT)) { if (absoffset < fdt_off_mem_rsvmap(fdt)) - return NULL; + return false; if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry)) - return NULL; + return false; } + + return true; +} + +static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) +{ + if (!fdt_is_mem_rsv(fdt, n)) + return NULL; return fdt_mem_rsv_(fdt, n); } @@ -191,7 +199,8 @@ int fdt_num_mem_rsv(const void *fdt) int i; const struct fdt_reserve_entry *re; - for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { + for (i = 0; fdt_is_mem_rsv(fdt, i); i++) { + re = fdt_mem_rsv_(fdt, i); if (fdt64_ld_(&re->size) == 0) return i; } -- 2.25.1