A common example of a harmful abstraction, in C and C++, is a typedef of a pointer to an opaque name. The typedef conceals, when you read code using it, that the type is really a pointer, and so subject to all the excess operations provided for pointers in those languages. But one thing every C and C++ programmer always needs to know about a type they are working with is whether it is a pointer.
Every abstraction has an unavoidable cost. The value it provides has to exceed that cost for it not to be a liability. Usually the main cost is that it is not as comprehensively documented as its creator imagines (if at all), and the user cannot trust what it will do without tracing through and understanding what details and pitfalls it hides. The more comprehensive its documentation, the more time it takes to read and understand, and the more likely it is to be, or later become, inaccurate.
Thus, part of the job of every programmer is to distrust abstractions. An abstraction works on cases it has been seen to work on, but often cannot be trusted otherwise. This is what makes Standard Library abstractions valuable: you have confidence the implementation has been verified to match the specification, and the specification (1) has been carefully designed to avoid pitfalls and (2) documents them, where it cannot. J. Random Abstraction in your local library rarely gets that much attention.
Make your abstractions earn their keep.