tags:

views:

85

answers:

5

hi i am a student and just start learning low level c programming.i tried to understand read() and write() methods with this program.

#include <unistd.h>
#include <stdlib.h>
main()
{
    char *st;
    st=calloc(sizeof(char),2);//allocate memory for 2 char
    read(0,st,2);
    write(1,st,2);
}

i was expecting that it would give segmentation fault when i would try to input more than 2 input characters.but when i execute program and enter " asdf " after giving " as " as output it executes "df" command.

i want to know why it doesn't give segmentation fault when we assign more than 2 char to a string of size 2.and why is it executing rest(after 2 char)of input as command instead of giving it as output only?

also reading man page of read() i found read() should give EFAULT error,but it doesn't.

I am using linux.

+2  A: 

You ask read() to read no more than 2 characters (third parameters to read()) and so it overwrites no more than two characters in the buffer you supplied. That's why there's no reason for any erroneous behavior.

sharptooth
+3  A: 

Your read specifically states that it only wants two characters so that's all it gets. You are not putting any more characters into the st area so you won't get any segmentation violations.

As to why it's executing the df part, that doesn't actually happen on my immediate system since the program hangs around until ENTER is pressed, and it appears the program's I/O is absorbing the extra. But that immediate system is Cygwin - see update below for behaviour on a "real" UNIX box.

And you'll only get EFAULT if st is outside your address space or otherwise invalid. That's not the case here.


Update:

Trying this on Ubuntu 9, I see that the behaviour is identical to yours. When I supply the characters asls, the program outputs as then does a directory listing

That means your program is only reading the two characters and leaving the rest for the "next" program to read, which is the shell.

Just make sure you don't try entering:

asrm -rf /

(no, seriously, don't do that).

paxdiablo
On my ubuntu 8.04, I observe the same behaviour (ie df is executed). Since read is used, and not fread, There is no reason for the tty layer to discard the remaining char. The tty settings change the events that makes read return, but not the content of the tty buffer. echo > asdf\n | ./test would gives a different result, and only output as
shodanex
A: 

with read(0, st, 2); you read 2 chars from standard input. The rest of what you typed will not be accuired from the program, but will not be omitted, so the keystrokes are going back to the shell, from which your program started (which are df and enter).

Peter Miehle
Using the FILE * variable 'stdin' with read() seems like dubious advice. You probably meant the STDIN_FILENO macro.
unwind
thanks, changed
Peter Miehle
A: 

Since you only read 2 character, there is no problem. the df characters are not consume by your program, so they stay in the terminal buffer, and are consumed by the shell :

  • your program runs
  • you type asdf\n
  • your program reads asand leaves df\n in the tty buffer
  • you write the content of the st buffer to stdout
  • your program stops
  • the shell reads df\n from input and executes df command.

Fun things to try :

  • strace your program, to trace the system call : strace -e read, write ./yourprogram
  • read(0, st, 5)
shodanex
Not sure, but I think a program using buffered (cooked) IO will absorb the _entire_ line from the tty drivers before delivering two characters to the app. The remainder won't be available to the parent process. I tried this within Cygwin, perhaps you could try it on a proper Linux box for confirmation (or otherwise).
paxdiablo
On my ubuntu 8.04, I observe the same behaviour (ie df is executed).Since read is used, and not fread, There is no reason for the tty layer to discard the remaining char. I believe echo > asdf\n | ./test would give a different result, and only output as
shodanex
+1  A: 

When you read(), you specify how many bytes you want. You won't get more than that unless your libc is broken, so you'll never write beyond the end of your buffer as long as your count is never greater than the size of your buffer. The extra bytes remain in the stream, and the next read() will get them. And if you don't have a next read() in your app, the process that spawned it (which would normally be the shell) may see them, since spawning a console app from the shell involves attaching the shell's input and output streams to the process. Whether the shell sees and gets the bytes depends partly on how much buffering is done behind the scenes by libc, and whether it can/does "unget" any buffered bytes on exit.

cHao