Sometimes an interrupt service routine (ISR) is called without any apparent reason.
This happens immediately after a "legitimate" interrupt, if the flag in peripheral causing the interrupt is cleared late in the ISR
The root cause is, that it takes time, until a write from processor actually reaches the peripheral (from processor through its write buffer, the busmatrix, the AHB/APB bridge with its write buffer, getting synchronized in that bridge to the APB frequency) and then more time until the change from the peripheral propagates all the way through to NVIC (again through synchronizers from the APB clock domain to system/processor clock domain)1. This is exacerbated by the fact that peripherals may sit at slow APB buses, with clocks divided significantly down from the system clock.
The reason why this process is so complicated is, that these chips are not microcontrollers built tightly around a processing core and sharing its clock. Rather, they are systems-on-chip, SoC, equivalent to a whole computer from the past, stitched together more or less loosely from a processor core, peripherals, and an interconnection mesh (data and signalling).
Unfortunately, this problem is difficult to remove entirely.
Symptomatically, it's relatively easy - each interrupt source has to be qualified, i.e. the ISR has always to check, whether the flag causing the interrupt is indeed set in the peripheral and the program has to return from ISR if not. This is what the vast majority of users should do.
However, if one, by early clearing the interrupt source, would like to avoid the unnecessary calls to the interrupt entirely (and possibly avoiding the test, if there's only one single source for the interrupt), there's no much help - exact documentation is non-existent, the best one can do is test/benchmark and hope that he/she won't make any mistake. Note, that adding elements to the program, which potentially cause bus conflicts (e.g. DMA), can increase the latencies between processor and peripheral, thus re-introducing the problem which had possibly been removed in a simpler version of the program. This in most cases is best to be avoided, even at the cost of ineffective ISR, using the above "always verify the interrupt source" method. Lengthy ISR may almost safely guarantee that the verification is not needed; but then a bit of inefficiency usually won't hurt lengthy ISRs...
Using barrier instuctions (DSB or ISB) in the processor won't yield the required safety - the root cause is outside the scope of the processor, and dependent on the particular implementation of the busmatrix and peripherals.
This article in ARM/Keil's support describes the same problem. Note, that they don't acknowledge existence of any other source of delay, and the "second, system level buffer" mentioned there is assumed to be immediately on the processor's port, on the entry to the busmatrix. This is rarely the case, that's why the solution described there (performing any write) is not likely to help in most of the cases.
Selecting asynchronous ADC kernel clock may make this problem somewhat worse.
This gotcha describes a related problem, which occurs when pending interrupts are cleared outside an ISR.
1. A nice example illustrating the second part of the problem, i.e. propagation from peripheral (here: EXTI) to NVIC, is here.
2. You don't want to do this by RMW i.e. using &= or |=, and you don't want to use bit-banding to do this on Cortex-M3/M4-based mcus either. Here's why.