Search code examples
rustexc-bad-access

EXC_BAD_ACCESS when using Default::default()


I have what seems to be a simple struct where I implement the Default trait:

#[derive(Debug, PartialEq)]
pub enum AuthenticationType {
  Trust,
  AuthenticationCleartextPassword,
  AuthenticationMD5Password,
  AuthenticationSASL,
}

#[derive(Debug)]
pub struct Configuration {
  user: String,
  password: Option<String>,
  dbname: Option<String>,
  hostaddr: SocketAddr,
  authentication_type: AuthenticationType,
}

impl Configuration {
  pub fn new(user: String, password: Option<String>, dbname: Option<String>, hostaddr: SocketAddr, authentication_type: AuthenticationType) -> Self {
    Configuration {
      user,
      password,
      dbname,
      hostaddr,
      authentication_type,
    }
  }
}

impl Default for Configuration {
  fn default() -> Self {
    Configuration {
      hostaddr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5432),
      authentication_type: AuthenticationType::Trust,
      ..Default::default()
    }
  }
}

and a test for the default method that causes a stack overflow:

#[cfg(test)]
mod tests {

  use super::*;

  #[test]
  fn test_default_configuration() {
    let configuration = Configuration::default();
    //assert_eq!(configuration.authentication_type, AuthenticationType::Trust);
  }
}

Using VSCode to step into the default method I get an EXC_BAD_ACCESS when ..Default::default() is called.

I'm sure I'm missing something obvious but can't figure out what it is?


Solution

  • impl Default for Configuration {
      fn default() -> Self {
        Configuration {
          hostaddr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5432),
          authentication_type: AuthenticationType::Trust,
          ..Default::default()
        }
      }
    }
    

    In the above code Default::default() has an inferred return type of Configuration, because the .. syntax indicates that you want to use the field values specified and the field values from a value of type Configuration.

    Since Default::default() has an inferred return type of Configuration, it calls the default implementation for Configuration, which results in infinite recursion.

    The infinite recursion results in a stackoverflow which manifests as accessing invalid memory off the end of the stack, resulting in EXC_BAD_ACCESS.