(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
analyzer/
torture/
asm-x86-linux-wfx_get_ps_timeout-reduced.c
       1  /* { dg-do compile { target x86_64-*-* } } */
       2  /* { dg-require-effective-target lp64 } */
       3  
       4  /* Reproducer for false positive from -Wanalyzer-null-dereference seen
       5     in Linux kernel (drivers/staging/wfx/sta.c; GPL-2.0) due to
       6     the analyzer not grokking that array_index_mask_nospec is
       7     effectively pure, and thus not realizing that array_index_no_spec
       8     is also pure, leading to wdev_to_wvif not being treated as pure,
       9     and thus able to return non-NULL and then NULL.  */
      10  
      11  typedef unsigned char u8;
      12  #define NULL ((void *)0)
      13  
      14  /* Types.  */
      15  
      16  struct ieee80211_vif {
      17    int placeholder;
      18    /* snip */
      19    u8 drv_priv[];
      20  };
      21  
      22  struct wfx_dev {
      23    /* snip */
      24    struct ieee80211_vif *vif[2];
      25    /* snip */
      26  };
      27  
      28  struct wfx_vif {
      29    struct wfx_dev *wdev;
      30    struct ieee80211_vif *vif;
      31    /* snip */
      32  };
      33  
      34  /* Copied from arch/x86/include/asm/barrier.h */
      35  
      36  static inline unsigned long array_index_mask_nospec(unsigned long index,
      37  		unsigned long size)
      38  {
      39  	unsigned long mask;
      40  
      41  	asm volatile ("cmp %1,%2; sbb %0,%0;"
      42  			:"=r" (mask)
      43  			:"g"(size),"r" (index)
      44  			:"cc");
      45  	return mask;
      46  }
      47  
      48  /* Simplified from include/linux/kernel.h */
      49  #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
      50  
      51  /* Simplified from include/linux/nospec.h */
      52  
      53  #define array_index_nospec(index, size)					\
      54  ({									\
      55  	typeof(index) _i = (index);					\
      56  	typeof(size) _s = (size);					\
      57  	unsigned long _mask = array_index_mask_nospec(_i, _s);		\
      58  	/* snip */							\
      59  	(typeof(_i)) (_i & _mask);					\
      60  })
      61  
      62  /* Simplified from drivers/staging/wfx/wfx.h */
      63  
      64  static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id) {
      65    vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif));
      66    if (!wdev->vif[vif_id]) {
      67      return NULL;
      68    }
      69    return (struct wfx_vif *)wdev->vif[vif_id]->drv_priv;
      70  }
      71  
      72  struct ieee80211_vif *test (struct wfx_vif *wvif) {
      73    if (wdev_to_wvif(wvif->wdev, 1))
      74      return wdev_to_wvif(wvif->wdev, 1)->vif; /* { dg-bogus "dereference of NULL" } */
      75    else
      76      return NULL;
      77  }