revert to malloc implementation, support empty string