Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 May 2002 22:23:24 -0400 (EDT)
From:      Garrett Wollman <wollman@khavrinen.lcs.mit.edu>
To:        standards@freebsd.org
Cc:        jdp@freebsd.org
Subject:   Q&D implementation of dlfunc()
Message-ID:  <200205290223.g4T2NOMD009676@khavrinen.lcs.mit.edu>

next in thread | raw e-mail | index | archive | help
Those who follow the Austin Group lists will be aware of an issue
raised (and not resolved there) about the unsuitability of the return
type of dlsym() for its most common use.

Specifically, Standard C leaves undefined the result of converting a
data pointer to a function pointer.  Some compilers and lint programs
may warn about doing this conversion, even though it is perfectly
well-defined on all of the architectures FreeBSD supports.  An
alternate interface, dlfunc(), has been proposed to remedy this
problem, by providing an alternate interface to dlsym() which returns
a function pointer type.  However, the POSIX committee is loath to
add a new interface without some prior art.  The following patch
implements dlfunc() in order to provide that prior art.

-GAWollman

Index: include/dlfcn.h
===================================================================
RCS file: /home/ncvs/src/include/dlfcn.h,v
retrieving revision 1.14
diff -u -r1.14 dlfcn.h
--- include/dlfcn.h	23 Mar 2002 17:24:53 -0000	1.14
+++ include/dlfcn.h	29 May 2002 02:05:42 -0000
@@ -63,10 +63,22 @@
 	void		*dli_saddr;	/* Address of nearest symbol */
 } Dl_info;
 
+/*
+ * The actual type declared by this typedef is immaterial, provided that
+ * it is a function pointer.  Its purpose is to provide a return type for
+ * dlfunc() which can be cast to a function pointer type without depending
+ * on behavior undefined by the C standard which might trigger a compiler
+ * diagnostic.  We intentionally declare a very unlikely type signature
+ * to force a diagnostic should the application not cast the return value
+ * of dlfunc() appropriately.
+ */
+typedef void (*__dlfunc_t)(void (*)(char, short, int, ...));
+
 __BEGIN_DECLS
 int dladdr(const void *, Dl_info *);
 int dlclose(void *);
 const char *dlerror(void);
+__dlfunc_t dlfunc(void *, const char *);
 void dllockinit(void *_context,
 		void *(*_lock_create)(void *_context),
 		void (*_rlock_acquire)(void *_lock),
Index: lib/libc/gen/Makefile.inc
===================================================================
RCS file: /home/ncvs/src/lib/libc/gen/Makefile.inc,v
retrieving revision 1.86
diff -u -r1.86 Makefile.inc
--- lib/libc/gen/Makefile.inc	21 Mar 2002 06:45:32 -0000	1.86
+++ lib/libc/gen/Makefile.inc	29 May 2002 01:53:50 -0000
@@ -8,7 +8,7 @@
 	alarm.c arc4random.c assert.c basename.c \
 	clock.c closedir.c confstr.c \
 	crypt.c ctermid.c daemon.c devname.c dirname.c disklabel.c \
-	dlfcn.c drand48.c erand48.c err.c errlst.c \
+	dlfcn.c dlfunc.c drand48.c erand48.c err.c errlst.c \
 	exec.c fmtcheck.c fnmatch.c fstab.c ftok.c fts.c \
 	getbootfile.c getbsize.c \
 	getcap.c getcwd.c getdomainname.c getgrent.c getgrouplist.c \
Index: lib/libc/gen/dlopen.3
===================================================================
RCS file: /home/ncvs/src/lib/libc/gen/dlopen.3,v
retrieving revision 1.19
diff -u -r1.19 dlopen.3
--- lib/libc/gen/dlopen.3	4 Feb 2002 10:44:15 -0000	1.19
+++ lib/libc/gen/dlopen.3	29 May 2002 02:11:10 -0000
@@ -32,11 +32,11 @@
 .\" @(#) dlopen.3 1.6 90/01/31 SMI
 .\" $FreeBSD: src/lib/libc/gen/dlopen.3,v 1.19 2002/02/04 10:44:15 sobomax Exp $
 .\"
-.Dd September 24, 1989
+.Dd May 28, 2002
 .Os
 .Dt DLOPEN 3
 .Sh NAME
-.Nm dlopen , dlsym , dlerror , dlclose
+.Nm dlopen , dlsym , dlfunc , dlerror , dlclose
 .Nd programmatic interface to the dynamic linker
 .Sh LIBRARY
 .Lb libc
@@ -46,6 +46,8 @@
 .Fn dlopen "const char *path" "int mode"
 .Ft void *
 .Fn dlsym "void *handle" "const char *symbol"
+.Ft __dlfunc_t
+.Fn dlfunc "void *handle" "const char *symbol"
 .Ft const char *
 .Fn dlerror "void"
 .Ft int
@@ -220,11 +222,28 @@
 condition which may be queried with
 .Fn dlerror .
 .Pp
+.Fn dlfunc
+implements all of the behavior of
+.Fn dlsym ,
+but has a return type which can be cast to a function pointer without
+triggering compiler diagnostics.
+.Po Fn dlsym
+returns a data pointer; in the C standard, conversions between
+data and function pointer types are undefined.  Some compilers and
+.Xr lint 1
+utilities warn about such casts.
+.Pc
+The precise return type of
+.Fn dlfunc
+is unspecified; applications must cast it to an appropriate function pointer
+type.
+.Pp
 .Fn dlerror
 returns a null-terminated character string describing the last error that
 occurred during a call to
 .Fn dlopen ,
 .Fn dlsym ,
+.Fn dlfunc ,
 or
 .Fn dlclose .
 If no such error has occurred,
@@ -277,10 +296,11 @@
 .Fl aout
 option to the C language compiler.
 .Sh ERRORS
-.Fn dlopen
+.Fn dlopen ,
+.Fn dlsym ,
 and
-.Fn dlsym
-return the null pointer in the event of errors.
+.Fn dlfunc
+return a null pointer in the event of errors.
 .Fn dlclose
 returns 0 on success, or -1 if an error occurred.
 Whenever an error has been detected, a message detailing it can be
--- /dev/null	Tue May 28 22:11:01 2002
+++ lib/libc/gen/dlfunc.c	Tue May 28 21:53:38 2002
@@ -0,0 +1,25 @@
+/*
+ * This source file is in the public domain.
+ * Garrett A. Wollman, 2002-05-28.
+ */
+
+#include <dlfcn.h>
+
+/*
+ * Implement the dlfunc() interface, which behaves exactly the same as
+ * dlsym() except that it returns a function pointer instead of a data
+ * pointer.  This can be used by applications to avoid compiler warnings
+ * about undefined behavior, and is intended as prior art for future
+ * POSIX standardization.  This function requires that all pointer types
+ * have the same representation, which is true on all platforms FreeBSD
+ * runs on, but is not guaranteed by the C standard.
+ */
+__dlfunc_t
+dlfunc(void *handle, const char *symbol)
+{
+	__dlfunc_t rv;
+
+	*(void **)&rv = dlsym(handle, symbol);
+	return (rv);
+}
+

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-standards" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200205290223.g4T2NOMD009676>