It turns out the gl calls in the destructor were, actually, the problem. Once I moved all the appropriate glDelete calls inside their own Cleanup() function, and called that at the right time, the issue was resolved. Thanks everyone. :)
And I'm not sure if every vec3 input is converted to a vec4 implicitly, but it seems like it would - after all, the shader doesn't know if the first vec3 you're passing to it is position or color data or something else.
It's good to hear your problem is resloved. I put a macro after every OpenGL call that resolves to a check on current context and OpenGL error check in debug mode and nothing in release. It makes the code run a bit slower but helps catch some of these things.
I am looking forward to the callback error code working the new drivers.