0
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
    
    char wd[10];

    if(getcwd(wd,BUFSIZ) == NULL){   //BUFSIZ = 8192
            perror("getcwd");
            exit(1);
    }
    printf("wd = %s\n",wd);
}

This C code works well in Ubuntu Linux 20. The size of buffer wd is 10 but if I print the wd, it can output a string that is over size 10.

I think that the function uses the pointer of wd regardless of size, so it can work well but it can also print dummy string. Is it right?

//Edit :

printf("wd2 = %s\n",wd2); -> printf("wd = %s\n",wd);

  • 1
    If you lie to the function about how much space is available to store the directory name, weird stuff can happen. Welcome to undefined behavior. – Shawn Oct 07 '22 at 02:46
  • 4
    [man 3 getcwd](https://man7.org/linux/man-pages/man2/getcwd.2.html) tells you exactly what you need to know. man pages, although cryptic at first, are concise descriptions on exactly how to use individual functions. Why would you `wd[10]` and then `getcwd(wd,BUFSIZ)`??? `10` ain't `8192`... – David C. Rankin Oct 07 '22 at 02:49
  • 1
    Why not `#include ` and then `char wd[PATH_MAX];` and then `if (getcwd (wd, PATH_MAX) == NULL) { ... }`? – David C. Rankin Oct 07 '22 at 02:52
  • Also, why would you ignore compiler errors? If you `char wd[10];` and try and `printf("wd2 = %s\\n",wd2);` -- how is the compiler to know what `wd2` is? It's not declared, defined or initialized anywhere??? -- and then there is the problem with `\\n` (that is an explicit `'n'` not a newline `'\n'`) – David C. Rankin Oct 07 '22 at 02:55
  • I'm sorry. I edited the code to give question. But I don't change wd2 to wd. – Jaemin Ryu Oct 07 '22 at 03:00

2 Answers2

1

You lie to getcwd about buffer size.

getcwd does not magically know the buffer size. Buffers which know their own size is not a C language feature. That's why getcwd needs the size parameter!

So, getcwd happily writes beyond end of array.

In C, this is Undefined Behavior. Anything can happen, and "anything" includes what you observe here.

hyde
  • 60,639
  • 21
  • 115
  • 176
0

Alright, let's get you straightened out:

  1. You can't declare wd as char[10] and then try and read 8192 bytes into it -- won't work,
  2. You can't declare wd and then try and output wd2 -- won't work, and your compiler should be screaming errors at you,
  3. \\n is a literal "\n" (two \\ are a literal '\') not a newline '\n',
  4. #include <limits.h> and #define _GNU_SOURCE to make PATH_MAX available -- which is the maximum length a pathname can be on your system (if any) -- then read that many bytes with getcwd().

Putting it altogether, you can do:

#define _GNU_SOURCE      /* needed for PATH_MAX */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>      /* needed for PATH_MAX */

int main (void) {
    
  char wd[PATH_MAX];    /* define your buffer with size PATH_MAX */ 

  if (getcwd (wd, PATH_MAX) == NULL) {  /* get the same number of bytes */
    perror("getcwd");
    exit(1);
  }
  
  printf ("wd = %s\n", wd);   /* output the results using same variable */
}

Compile

With the source in getcwd.c and ALWAYS compiling with FULL WARNINGS ENABLED, you can do:

$ gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -Ofast -o bin/getcwd getcwd.c

(note: I have a bin directory in my current directory that I put executables in to keep from cluttering my source directory)

Don't accept code until it compiles without warning. Add -Werror to treat warnings as errors so you can't cheat.

Example Use/Output

Running the program yields:

$ ./bin/getcwd
wd = /home/david/dev/src-c/tmp/debug

Let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • 1
    The situation the OP asks about involves that their code *does* seem to work, contrary to what your (1) predicts. Your (2) and (3) apparently refer to typos that the OP corrected at about the same time that this answer was posted. And [`PATH_MAX`'s name is misleading](https://eklitzke.org/path-max-is-tricky). It is *not* the maximum length of a path on the filesystem, though it might nevertheless be an ok choice for the buffer size in this case. – John Bollinger Oct 07 '22 at 03:11
  • @JohnBollinger yep, I can only answer the question as it was written at the time of the answer. `1)` only works for paths less than 9-char -- possible, but horribly unlikely and the risk of UB is ever-present. According to GNU, `PATH_MAX` is `"The uniform system limit (if any) for the length of an entire file name"`, so the `if any` weasel words give some wiggle room, but for all practical purposes, it's the best choice. (updated to reflect edit and weasel words) – David C. Rankin Oct 07 '22 at 03:16