# include "Command.h" # include "IMAPSession.h" # include "IMAPServer.h" # include "Log.h" namespace mail { int IMAPCommand::processCommand(coreutils::ZString &request, core::TCPSession &session) { // session.server is a TCPServer* (pointer) - C-style-casting the // POINTER VALUE directly to a reference type does not dereference // it. Per C++'s reference-cast rules this falls back to // reinterpret_cast, which for an expression that is not // itself an object is *reinterpret_cast(&expr) - i.e. it took // the address of the `session.server` POINTER FIELD ITSELF (8 // bytes, wherever that field happens to live inside the // TCPSession/IMAPSession object) and read an entire IMAPServer's // worth of memory starting there, not the real IMAPServer object // the pointer actually points to. Confirmed live via gdb: fields // read off the "IMAPServer" this produced were complete garbage // (a null EPoll reference, a socket descriptor of -136794095). // The compiler's own "does not dereference pointer" warning on // this exact line, present on every build all session, was // reporting precisely this. Dereferencing the pointer first // (*session.server, a real TCPServer&) makes the cast to // IMAPServer& a normal, correct base-to-derived downcast. // CommandList::processRequest() (ServerCore) calls request.reset() // right before dispatch - the cursor lands at the true start of // the whole command line, which STILL includes the command word // itself ("LOGIN", "FETCH", ...), not just past it. SMTP handlers // never noticed because they read arguments via request[N] (the // pre-split list, built independently of cursor position) rather // than the cursor - every IMAP handler here parses off the raw // cursor instead (see IMAPArgs.h's own doc comment for why), so // without this, every handler's first nextArgument() call was // reading the command word itself as if it were the first real // argument (confirmed live: LOGIN "user" "pass" produced // userArg=="LOGIN", passArg=="user", with "pass" never read at // all). Discarding it here, once, centrally, is simpler and less // error-prone than every individual handler remembering to do it. request.getTokenExclude(" "); return processCommand(request, (IMAPSession &)session, (IMAPServer &)(*session.server)); } }