(Unfortunately I have learned this the hard way)
An example slow input for this pattern is a bunch of spaces followed by a non-whitespace character. It tries starting at each space, and from each starting point it has to keep checking characters until it runs into the non-space character (at which point it realizes the pattern doesn't match). So it looks at about n characters, then about n - 1, then n - 2, etc, which adds up to O(n^2)
A short Python example
>>> import timeit
>>> timeit.timeit("re.findall(r'\s+$', 'a' + ' ' * 100)", setup="import re")
0.82954529998824
>>> timeit.timeit("re.findall(r'\s+$', ' ' * 100 + 'a')", setup="import re")
58.42058260005433
(but this is not in any way specific to Python, the actual problem I had was in Java)
if you forgot: https://stackstatus.tumblr.com/post/147710624694/outage-postmortem-july-20-2016
features that cannot be implemented with finite automata include backreferences, lookaround (because it may be in the middle of the pattern), balancing groups, recursion (which can emulate balancing groups), and subroutines (which are basically more powerful recursion). if you have any of these features, you can craft a pattern and input that obligates exponential time.
these are, however, very powerful and useful features so some engines (perl, python, .NET, etc) favor to keep them rather than make it safe to use regex on arbitrary user inputs (as re2/golang, rust, etc do). the engines often work completely differently as a result, and the recursive kind that works with the fancy features has all the problems with quadratic matching @amypercent and stackoverflow tripped over without lots of extremely fancy footwork (as @opoponax mentioned in the comments).
i don't know off the top of my head of any engines that will compile a matcher with finite automata iff it is safe to do so, but they should
