[PATCH] D105169: [Clang/Test]: Rename enable_noundef_analysis to disable-noundef-analysis and turn it off by default

Hyeongyu Kim via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 28 17:50:26 PST 2021


hyeongyukim added a comment.

In D105169#3116810 <https://reviews.llvm.org/D105169#3116810>, @nathanchance wrote:

> Prior to the latest revert (fd9b099906c61e46574d1ea2d99b973321fe1d21 <https://reviews.llvm.org/rGfd9b099906c61e46574d1ea2d99b973321fe1d21>), the Linux kernel's binary verifier (`objtool`) points out an issue when building with ThinLTO and `-fsanitize=integer-divide-by-zero`. I have no idea if this is an issue with the tool or this series. A simplified reproducer:
>
>   $ cat ravb_main.i
>   int ravb_set_gti_ndev_rate;
>   unsigned int ravb_set_gti_ndev_inc;
>   void ravb_set_gti_ndev() {
>     ravb_set_gti_ndev_inc = 1000000000;
>     ravb_set_gti_ndev_inc = ravb_set_gti_ndev_inc / ravb_set_gti_ndev_rate;
>     if (ravb_set_gti_ndev_inc)
>       _dev_err(ravb_set_gti_ndev_inc);
>   }
>   
>   $ clang -std=gnu89 -O2 -flto=thin -fsanitize=integer-divide-by-zero -c -o ravb_main.o ravb_main.i
>   
>   $ llvm-ar cDPrsT ravb.o ravb_main.o
>   
>   $ ld.lld -m elf_x86_64 -r -o ravb.lto.o --whole-archive ravb.o
>   
>   $ ./objtool orc generate --no-fp --no-unreachable --retpoline --uaccess --mcount --module ravb.lto.o
>   ravb.lto.o: warning: objtool: .text.ravb_set_gti_ndev: unexpected end of section
>
> With LLVM 13.0.0, there is no warning with those commands. The original and reduced `.i` file, interestingness test, and static `objtool` binary are available here <https://github.com/nathanchance/creduce-files/tree/2010d2dc4fd217948a734d8bfb6be5460222b6b4/D105169>.

I checked the reason why Objtool makes a warning.

  cont.thread:                                      ; preds = %entry
    tail call void @__ubsan_handle_divrem_overflow(i8* bitcast ({ { [12 x i8]*, i32, i32 }, { i16, i16, [15 x i8] }* }* @1 to i8*), i64 1000000000, i64 0) #3, !nosanitize !8
    br label %if.then
  
  cont:                                             ; preds = %entry
    %div = udiv i32 1000000000, %0
    store i32 %div, i32* @ravb_set_gti_ndev_inc, align 4, !tbaa !4
    %tobool.not = icmp ugt i32 %0, 1000000000
    br i1 %tobool.not, label %if.end, label %if.then
  
  if.then:                                          ; preds = %cont.thread, %cont
    %div3 = phi i32 [ poison, %cont.thread ], [ %div, %cont ]
    %call = tail call i32 (i32, ...) bitcast (i32 (...)* @_dev_err to i32 (i32, ...)*)(i32 noundef %div3) #3
    br label %if.end

This IR code is an IR that has not passed the optimization pass completely.
This code calculates the division only if `ravb_set_gti_ndev_rate` is non-zero and it calls `ubsan_handle_divrem_overflow` function to handle UB if `ravb_set_gti_ndev_rate` is zero.
So far, there is no warning. But a warning occurs when this code passes the SimpleCFG optimization.

  cont.thread:                                      ; preds = %entry
    tail call void @__ubsan_handle_divrem_overflow(i8* bitcast ({ { [12 x i8]*, i32, i32 }, { i16, i16, [15 x i8] }* }* @1 to i8*), i64 1000000000, i64 0) #3, !nosanitize !8
    unreachable
  
  cont:                                             ; preds = %entry
    %div = udiv i32 1000000000, %0
    store i32 %div, i32* @ravb_set_gti_ndev_inc, align 4, !tbaa !4
    %tobool.not = icmp ugt i32 %0, 1000000000
    br i1 %tobool.not, label %if.end, label %if.then
  
  if.then:                                          ; preds = %cont
    %call = tail call i32 (i32, ...) bitcast (i32 (...)* @_dev_err to i32 (i32, ...)*)(i32 noundef %div) #3
    br label %if.end
  
  if.end:                                           ; preds = %if.then, %cont
    ret void
  }

After it passes the SimplyCFG, the `br` instruction was changed to the `unreachable` instruction in `cont.thread` block.

This patch added noundef to the parameter of the `_dev_err` function, making the `%div3` unable to be Poison.
It is impossible to jump from the `cont.thread` block to `if.then` block, so `br` instruction was changed to `unreachable` instruction.
It would be nice to remove the unreachable block, but the above IR is not wrong because it is UB when `ravb_set_gti_ndev_rate` is zero.

There seems to be no existing problem in clang, and I think we can bypass this warning by adding a code that checks whether the `gravb_set_gti_ndev_rate` is zero or not as follows.

  int ravb_set_gti_ndev_rate;
  unsigned int ravb_set_gti_ndev_inc;
  void ravb_set_gti_ndev() {
    ravb_set_gti_ndev_inc = 1000000000;
    ravb_set_gti_ndev_inc = ravb_set_gti_ndev_inc / ravb_set_gti_ndev_rate;
    if (ravb_set_gti_ndev_rate != 0)
      if (ravb_set_gti_ndev_inc)
        _dev_err(ravb_set_gti_ndev_inc);
  }

@nathanchance How about changing the existing test code as above?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105169/new/

https://reviews.llvm.org/D105169



More information about the cfe-commits mailing list