There are several ways in which the current USB implementation is unnecessarily profligate in its use of RAM. The simplest to fix is change to prototypes for the HAL routines that read descriptor strings to take const -- yes I know I can make my strings const, but then I get a bunch of compiler warnings and have to read the code to make sure it doesn't actually do something it shouldn't. If a routine doesn't modify a string parameter, that parameter should be const.
The second is the stmxxx_hal_pcd.h header which defines a (large) ram data structure to hold all 15 endpoints. Really, this should be a compile time define. It's a rare configuration (especially using the HAL which doesn't support any but the simplest USB devices) that uses more than a handful of endpoints. I resent loosing a bunch of RAM because of sloppy programming.