views:

80

answers:

4

Hi, I'm currently working on an FTP client written in C, and it's working pretty good. I was successful in writing a function that connects to an FTP server and logs in with a username or password, but I'm having a problem with returning errors. I have setup a struct FTPError {}; with 3 fields:

  1. int An error code
  2. int An FTP error domain (specific to my function)
  3. char[256] A user readable description

The caller of the function passes a structure by reference to the function and I fill it with the data. But I'm struggling with filling the user readable string (char[256]). I fill the string with strcpy, but when I call it, my program signals a SIGABRT. I present you a simplified piece of my code:

struct FTPError {
    int status;
    int domain;
    char message[FTP_ERROR_MAX];
};

typedef int FTPConnection;

FTPConnection FTPConnect(const char *hostname, const char *username, const char *password, struct FTPError *errn) {
    // Very much code I wrote that connects to the server,
    // sends the USER command to the FTP server, sends the
    // PASS command to the FTP server and succeeds in
    // logging in

    int socket = /* socket file descriptor */

    // Success
    if(success == 1) {
        if(errn) {
            // when I comment the line below, no signal is sent
            strcpy(errn->message, "User successfully loged in");
            errn->status = 230;
            errn->domain = kServerReplyDomain;
        }
    }

    // return the file descriptor
    return sockfd;
}

I thank all the dedicated people here to help me again, ief2

PS: This what Xcode gives me in the error console:

Program loaded.
run
[Switching to process 2566]
Running…
SOCK: 3
Program received signal:  “SIGABRT”.
sharedlibrary apply-load-rules all
kill
quit

0x00007fff824c03cc  <+0000>  mov    $0x2000025,%eax
0x00007fff824c03d1  <+0005>  mov    %rcx,%r10
0x00007fff824c03d4  <+0008>  syscall 
0x00007fff824c03d6  <+0010>  jae    0x7fff824c03dd <__kill+17> --> (points this line) 
0x00007fff824c03d8  <+0012>  jmpq   0x7fff82560a8c <cerror>
0x00007fff824c03dd  <+0017>  retq 

3 __kill
2 __abort
1 __stack_chk_fail
0 main

PPS: I was asked to call the code that calls the function:

int main (int argc, const char * argv[]) {
    struct FTPError reply;
    FTPConnection socket;

    socket = FTPConnect("ftp.belnet.be", "anonymous", "pwd", &reply);

    printf("SOCK: %d\n", socket);

    return 0;
}
+2  A: 

Most probably the errn pointer that is given to the function is not initialized properly, or otherwise invalid. Otherwise also FTP_ERROR_MAX could be a too small number, so that the strcpy() produces a buffer overflow.

sth
Sorry, stupid question, FTP_ERROR_MAX was indeed wrong, I defined it, but didn't give it a value :$
Ief2
Its default value was then 1, which is too short to hold any non-empty C string. This one time when the fact that `#define foo` has a well-defined meaning hurts you. If the meaning had been some other kind of defined and "true" value, then the `struct FTPError` declaration would not have compiled. This is also a good use for a compile time assertion in the vicinity of your `FTPConnect` implementation that validates that the member is too large enough for the longest error message you know of.
RBerteig
A: 

Are you sure you're passing a memory allocated structure and not a non-allocated pointer? The call should be like:

FTPError myError;
FTPConnect(host, user, password, &myError);

otherwise if you prefer working with a pointer:

FTPError* myError = (FTPError*) malloc(sizeof(FTPError));
FTPConnect(host, user, password, myError);
vulkanino
A: 

From what it says, I'd guess that you corrupted your stack with some of the other code and that it just shows up here at that place.

Anyhow, to be sure you should always initialize your errn structure with something like

 struct FTPError reply = { .status = 0 };
Jens Gustedt
A: 

try a save strcpy variation instead:

strncpy(errn->message, "any string with unknown length", FTP_ERROR_MAX-1 );
errn->message[ FTP_ERROR_MAX-1 ] = 0;