Reentrancy. Several pieces of functionality in Solidity can have fallback functions or hooks on specific actions. When these hooks are triggered (mid-smart contact), an attacker can run their own code. If the state of the contract was not updated already but money sent, then this can be called recursively to bypass the validations in place.
Integer Over/underflows: There is a limit to how large a number in Ethereum can be. For instance, a uint8 has a max value of 256 and a minimum size of 0. If the arithmetic goes too positive or too negative, then this can wrap back around.
Unexpected Ether: Money can be force-sent to a contract by using either the self-destruct or suicide functions. While doing validation on the data, this could be used to manipulate the service or turn on unexpected functionality.
Delegatecall: Call and DELEGATECALL are used for making function calls to an external function. The only difference is that DELEGATECALL is called within the context of the smart contract itself. When dealing with libraries, ownership and state variables need to be considered.
Bad RNG. Randomness is hard to generate in the blockchain. Some people try but things can be predicted in a variety of ways.
Frontrunning. Manipulating the chain of events by looking into the pool of available transactions and putting yours in at the right time. Or, taking an answer then submitting yourself with a higher gas price to KNOW yours will be used.
The post has a few other interesting bugs of Ethereum that are not as common now-a-days, such as Bad Constructors and unchecked return values. Additionally, some quirks are mentioned about one time addresses and other things. Overall, amazing post with great examples.