Protecting stdin Within A Library

C

ccdrbrg

What is the best way to protect stdin within a library?

I am writing a terminal based program that provides plugin
capability using the dlopen() API.

Sequencing program commands (typed) and library input
prompts will not happen if stdin is supplied by pipe
or redirection.

So, I would like to include a statement in the pluggin
header that disables stdin only within the pluggin's scope.
By disable, I expect the statement would result in a
compiler error.

There is also fd 0 to contend with.

Any suggestions would be much appreciated.

Chad
 
W

Walter Roberson

What is the best way to protect stdin within a library?
I am writing a terminal based program that provides plugin
capability using the dlopen() API.

dlopen() is not part of standard C, so this group likely will
not be able to come up with the best answer for your question.

Sequencing program commands (typed) and library input
prompts will not happen if stdin is supplied by pipe
or redirection.
So, I would like to include a statement in the pluggin
header that disables stdin only within the pluggin's scope.
By disable, I expect the statement would result in a
compiler error.

stdin is defined by the C89 standard to be a macro [that
is an expression that will give the appropriate FILE*].

This suggests that in theory you could #undef stdin
and #define stdin to be something incompatible that would
generate a compile error if used.

There is also fd 0 to contend with.

File descriptors are not actually part of the C standard either.
They are very common, and have well defined semantics under
the POSIX 1003.1 standard, but they are technically extensions to C.


I am not clear as to what exactly you are trying to protect
against. Are you trying to protect against the plugin opening
(even by way of freopen()) stdin, on the grounds that the prompts
will not happen if the user is not careful enough to use
pty's? Or are you trying to prevent the user from reading
an already established stdin ?

If you are trying to stop the user from using stdin then you
are going to have some difficulties, as a determined user could,
in a typical installation, use something like (stdout-1) or (stderr-2)
[commonly, the expressions for stdin, stdout, stderr are
in terms of addresses of elements of an array that holds all 3,
so simple pointer arithmetic can be used to get a handle on the
other elements.] And users could easily look in their <stdio.h>
and use the expressions directly instead of through the
stdin macro.

If you want users to be able to write plugins that deal with
I/O but you want to protect stdin then you might need to
provide your own fopen() and so on that would end up being what
the user linked against. But that gets into deep questions about
what the symbol resolution order is when you do a dlopen(),
and questions about whether your system has an internal
equivilent to fopen() et al. that you could access from your
replacement routines.


I don't know what it would do to program efficiency, but is
an alternative strategy perhaps in order? When you are calling
those 'sequenced commands' and library routines, would it make
sense for you to have preserved a copy of stdin, and to
restore it into place as the active stdin before calling the
routines? Potentially you could do some optimization about this,
not doing the re-activation unless user-provided code had been
called since the last activation.
 
K

Keith Thompson

stdin is defined by the C89 standard to be a macro [that
is an expression that will give the appropriate FILE*].

No, stdin, stdout, and stderr are

expressions of type "pointer to FILE" that point to the FILE
objects associated, respectively, with the standard error, input,
and output streams.

The wording is identical in C90 and C99. They may be macros (and
commonly are), but they aren't required to be.
This suggests that in theory you could #undef stdin
and #define stdin to be something incompatible that would
generate a compile error if used.

Even if stdin is a macro, that would affect explicit references to
stdin, but it won't necessarily affect functions like getchar() that
implicitly use stdin. If getchar() is a macro that refers to stdin,
redefining stdin will probably break getchar() (which is what you
want); if it's a function, it won't.
 
C

ccdrbrg

stdin is used in a loop in main() to receive input from the user
in the form of command lines.

If the library reads from stdin, they will get the next command
line if stdin has been supplied by pipe or redirection (i.e. not
interactively).

I did not expect a way to temporarily "lock up" stdin within the
library,
but if I can cause a compiler warning it will clue the pluggin author
he is
violating the design intent.

If I redefine stdin as "FILE *stdin = NULL;" in the pluggin header,
will this
create a new local stdin (file scope) separate from the global stdin?

Chad
 
G

Gordon Burditt

I did not expect a way to temporarily "lock up" stdin within the
library,
but if I can cause a compiler warning it will clue the pluggin author
he is
violating the design intent.

I recommend code in the Makefile that greps the source code for "stdin"
and deletes it if that string is found.
If I redefine stdin as "FILE *stdin = NULL;" in the pluggin header,
will this
create a new local stdin (file scope) separate from the global stdin?

No. It might initialize the global stdin. It might try to cause double
initialization of the global stdin (which would cause an error regardless
of whether the plugin author referenced it or not).

static FILE *stdin = NULL;

might work for what you want, but you'd better not include <stdio.h>
in code that uses your header (but you have to include it to get
a definition of FILE). Perhaps you'd be better off with:

static double stdin = 3.14159;

which should give compiler warnings with most uses of stdin.

Gordon L. Burditt
 
C

Chris Torek

[email protected] (Walter Roberson) said:
[...]
stdin is defined by the C89 standard to be a macro [that
is an expression that will give the appropriate FILE*].

No, stdin, stdout, and stderr are

expressions of type "pointer to FILE" that point to the FILE
objects associated, respectively, with the standard error, input,
and output streams.

The wording is identical in C90 and C99. They may be macros (and
commonly are), but they aren't required to be.

Walter Roberson is correct: they are required to be macros.
(The quote you gave is correct as well: the macros must expand
to such expressions.)

Note that even on systems that have three ordinary variables named
"stdin", "stdout", and "stderr", including <stdio.h> must have the
effect of doing:

#define stdin stdin
#define stdout stdout
#define stderr stderr

and indeed these three lines are found in some said:
Even if stdin is a macro, that would affect explicit references to
stdin, but it won't necessarily affect functions like getchar() that
implicitly use stdin. If getchar() is a macro that refers to stdin,
redefining stdin will probably break getchar() (which is what you
want); if it's a function, it won't.

Right. One would have to override all "implicit reference to stdin"
functions as well.
 
K

Keith Thompson

Chris Torek said:
(e-mail address removed)-cnrc.gc.ca (Walter Roberson) writes:
[...]
stdin is defined by the C89 standard to be a macro [that
is an expression that will give the appropriate FILE*].

No, stdin, stdout, and stderr are

expressions of type "pointer to FILE" that point to the FILE
objects associated, respectively, with the standard error, input,
and output streams.

The wording is identical in C90 and C99. They may be macros (and
commonly are), but they aren't required to be.

Walter Roberson is correct: they are required to be macros.
(The quote you gave is correct as well: the macros must expand
to such expressions.)

Note that even on systems that have three ordinary variables named
"stdin", "stdout", and "stderr", including <stdio.h> must have the
effect of doing:

#define stdin stdin
#define stdout stdout
#define stderr stderr

and indeed these three lines are found in some <stdio.h> files.

You and Walter are right, and I was wrong.

(C99 7.19.1p3 is a single sentence more than a page long. I missed
the fact that the definition of stdin, stdout, and stderr is part of
this sentence, which starts "The macros are ...".)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,429
Latest member
JacelynKit

Latest Threads

Top