vcrhonek pushed to expect (master). "Use different and probably better approach of fixing segfaults if Tcl is built with stubs and Expect is used directly from C program"

notifications at fedoraproject.org notifications at fedoraproject.org
Wed May 20 11:01:52 UTC 2015


From 9a7965843e92b2b41a15377168ea5b5c498db5c9 Mon Sep 17 00:00:00 2001
From: Vitezslav Crhonek <vcrhonek at redhat.com>
Date: Wed, 20 May 2015 13:01:29 +0200
Subject: Use different and probably better approach of fixing segfaults if Tcl
 is built with stubs and Expect is used directly from C program


diff --git a/expect-5.45-segfault-with-stubs.patch b/expect-5.45-segfault-with-stubs.patch
index 4cfeef0..eb02fe3 100644
--- a/expect-5.45-segfault-with-stubs.patch
+++ b/expect-5.45-segfault-with-stubs.patch
@@ -1,71 +1,553 @@
-Author: Sergei Golovan <sgolovan at debian.org>
-Description: This dirty hack fixes segfaults if Tcl is built with stubs
- and Expect is used directly from C program.
-Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=588817
-Example:
- #include <stdio.h>
- #include <tcl8.5/expect.h>
- int main()
- {
-     FILE *pipe;
-     char *some_command = "uname";
-     char datum;
-     pipe = exp_popen(some_command);
-     if (pipe == NULL) return 1;
-     while ((datum = getc (pipe)) != EOF)
- 	printf("%c",datum);
- }
-Example:
- #include <stdio.h>
- #include "expect.h"
- main()
- {
-     int fd = 0;
-     fd = exp_spawnl("echo", "echo", "Hello User: Whats up?", (char*) 0);
-     switch (exp_expectl(fd, exp_regexp, "ser:", 1, exp_end)) {
- 	case 1: {
- 	    printf("GOT ser:\n");
- 	    break;
- 	}
- 	default: {
- 	    printf("DEFAULT\n");
- 	    return 1;
- 	}
-     }
-     printf("Normal Exit\n");
-     return 0;
- }
-
---- expect-5.45.orig/exp_clib.c
-+++ expect-5.45/exp_clib.c
-@@ -117,7 +117,11 @@
+diff -up expect5.45/exp_clib.c.orig expect5.45/exp_clib.c
+--- expect5.45/exp_clib.c.orig	2010-09-01 00:20:27.000000000 +0200
++++ expect5.45/exp_clib.c	2015-05-19 12:01:22.413349423 +0200
+@@ -84,6 +84,8 @@ would appreciate credit if this program
+ #ifndef _STDLIB
+ #define _STDLIB
+ 
++#include <tcl.h>
++
+ extern void		abort _ANSI_ARGS_((void));
+ extern double		atof _ANSI_ARGS_((CONST char *string));
+ extern int		atoi _ANSI_ARGS_((CONST char *string));
+@@ -114,7 +116,6 @@ extern unsigned long	strtoul _ANSI_ARGS_
  #include <stdlib.h>		/* for malloc */
  #endif
  
 -#include <tcl.h>
-+#define ckalloc(x) Tcl_Alloc(x)
-+#define ckfree(x) Tcl_Free(x)
-+extern char *Tcl_ErrnoMsg(int err);
-+extern char *Tcl_Alloc(unsigned int size);
-+extern void Tcl_Free(char *ptr);
  #include "expect.h"
  #define TclRegError exp_TclRegError
  
-@@ -389,7 +389,7 @@
- 		FAIL("regexp too big");
+@@ -1465,6 +1466,467 @@ TclGetRegError()
+  */
+ 
+ /*
++ * following stolen from tcl8.0.4/generic/tclPosixStr.c
++ */
++
++/*
++ *----------------------------------------------------------------------
++ *
++ * Tcl_ErrnoMsg --
++ *
++ *     Return a human-readable message corresponding to a given
++ *     errno value.
++ *
++ * Results:
++ *     The return value is the standard POSIX error message for
++ *     errno.  This procedure is used instead of strerror because
++ *     strerror returns slightly different values on different
++ *     machines (e.g. different capitalizations), which cause
++ *     problems for things such as regression tests.  This procedure
++ *     provides messages for most standard errors, then it calls
++ *     strerror for things it doesn't understand.
++ *
++ * Side effects:
++ *     None.
++ *
++ *----------------------------------------------------------------------
++ */
++
++static
++char *
++Tcl_ErrnoMsg(err)
++    int err;                   /* Error number (such as in errno variable). */
++{
++    switch (err) {
++#ifdef E2BIG
++       case E2BIG: return "argument list too long";
++#endif
++#ifdef EACCES
++       case EACCES: return "permission denied";
++#endif
++#ifdef EADDRINUSE
++       case EADDRINUSE: return "address already in use";
++#endif
++#ifdef EADDRNOTAVAIL
++       case EADDRNOTAVAIL: return "can't assign requested address";
++#endif
++#ifdef EADV
++       case EADV: return "advertise error";
++#endif
++#ifdef EAFNOSUPPORT
++       case EAFNOSUPPORT: return "address family not supported by protocol family";
++#endif
++#ifdef EAGAIN
++       case EAGAIN: return "resource temporarily unavailable";
++#endif
++#ifdef EALIGN
++       case EALIGN: return "EALIGN";
++#endif
++#if defined(EALREADY) && (!defined(EBUSY) || (EALREADY != EBUSY ))
++       case EALREADY: return "operation already in progress";
++#endif
++#ifdef EBADE
++       case EBADE: return "bad exchange descriptor";
++#endif
++#ifdef EBADF
++       case EBADF: return "bad file number";
++#endif
++#ifdef EBADFD
++       case EBADFD: return "file descriptor in bad state";
++#endif
++#ifdef EBADMSG
++       case EBADMSG: return "not a data message";
++#endif
++#ifdef EBADR
++       case EBADR: return "bad request descriptor";
++#endif
++#ifdef EBADRPC
++       case EBADRPC: return "RPC structure is bad";
++#endif
++#ifdef EBADRQC
++       case EBADRQC: return "bad request code";
++#endif
++#ifdef EBADSLT
++       case EBADSLT: return "invalid slot";
++#endif
++#ifdef EBFONT
++       case EBFONT: return "bad font file format";
++#endif
++#ifdef EBUSY
++       case EBUSY: return "file busy";
++#endif
++#ifdef ECHILD
++       case ECHILD: return "no children";
++#endif
++#ifdef ECHRNG
++       case ECHRNG: return "channel number out of range";
++#endif
++#ifdef ECOMM
++       case ECOMM: return "communication error on send";
++#endif
++#ifdef ECONNABORTED
++       case ECONNABORTED: return "software caused connection abort";
++#endif
++#ifdef ECONNREFUSED
++       case ECONNREFUSED: return "connection refused";
++#endif
++#ifdef ECONNRESET
++       case ECONNRESET: return "connection reset by peer";
++#endif
++#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK))
++       case EDEADLK: return "resource deadlock avoided";
++#endif
++#if defined(EDEADLOCK) && (!defined(EDEADLK) || (EDEADLOCK != EDEADLK))
++       case EDEADLOCK: return "resource deadlock avoided";
++#endif
++#ifdef EDESTADDRREQ
++       case EDESTADDRREQ: return "destination address required";
++#endif
++#ifdef EDIRTY
++       case EDIRTY: return "mounting a dirty fs w/o force";
++#endif
++#ifdef EDOM
++       case EDOM: return "math argument out of range";
++#endif
++#ifdef EDOTDOT
++       case EDOTDOT: return "cross mount point";
++#endif
++#ifdef EDQUOT
++       case EDQUOT: return "disk quota exceeded";
++#endif
++#ifdef EDUPPKG
++       case EDUPPKG: return "duplicate package name";
++#endif
++#ifdef EEXIST
++       case EEXIST: return "file already exists";
++#endif
++#ifdef EFAULT
++       case EFAULT: return "bad address in system call argument";
++#endif
++#ifdef EFBIG
++       case EFBIG: return "file too large";
++#endif
++#ifdef EHOSTDOWN
++       case EHOSTDOWN: return "host is down";
++#endif
++#ifdef EHOSTUNREACH
++       case EHOSTUNREACH: return "host is unreachable";
++#endif
++#if defined(EIDRM) && (!defined(EINPROGRESS) || (EIDRM != EINPROGRESS))
++       case EIDRM: return "identifier removed";
++#endif
++#ifdef EINIT
++       case EINIT: return "initialization error";
++#endif
++#ifdef EINPROGRESS
++       case EINPROGRESS: return "operation now in progress";
++#endif
++#ifdef EINTR
++       case EINTR: return "interrupted system call";
++#endif
++#ifdef EINVAL
++       case EINVAL: return "invalid argument";
++#endif
++#ifdef EIO
++       case EIO: return "I/O error";
++#endif
++#ifdef EISCONN
++       case EISCONN: return "socket is already connected";
++#endif
++#ifdef EISDIR
++       case EISDIR: return "illegal operation on a directory";
++#endif
++#ifdef EISNAME
++       case EISNAM: return "is a name file";
++#endif
++#ifdef ELBIN
++       case ELBIN: return "ELBIN";
++#endif
++#ifdef EL2HLT
++       case EL2HLT: return "level 2 halted";
++#endif
++#ifdef EL2NSYNC
++       case EL2NSYNC: return "level 2 not synchronized";
++#endif
++#ifdef EL3HLT
++       case EL3HLT: return "level 3 halted";
++#endif
++#ifdef EL3RST
++       case EL3RST: return "level 3 reset";
++#endif
++#ifdef ELIBACC
++       case ELIBACC: return "can not access a needed shared library";
++#endif
++#ifdef ELIBBAD
++       case ELIBBAD: return "accessing a corrupted shared library";
++#endif
++#ifdef ELIBEXEC
++       case ELIBEXEC: return "can not exec a shared library directly";
++#endif
++#ifdef ELIBMAX
++       case ELIBMAX: return
++               "attempting to link in more shared libraries than system limit";
++#endif
++#ifdef ELIBSCN
++       case ELIBSCN: return ".lib section in a.out corrupted";
++#endif
++#ifdef ELNRNG
++       case ELNRNG: return "link number out of range";
++#endif
++#if defined(ELOOP) && (!defined(ENOENT) || (ELOOP != ENOENT))
++       case ELOOP: return "too many levels of symbolic links";
++#endif
++#ifdef EMFILE
++       case EMFILE: return "too many open files";
++#endif
++#ifdef EMLINK
++       case EMLINK: return "too many links";
++#endif
++#ifdef EMSGSIZE
++       case EMSGSIZE: return "message too long";
++#endif
++#ifdef EMULTIHOP
++       case EMULTIHOP: return "multihop attempted";
++#endif
++#ifdef ENAMETOOLONG
++       case ENAMETOOLONG: return "file name too long";
++#endif
++#ifdef ENAVAIL
++       case ENAVAIL: return "not available";
++#endif
++#ifdef ENET
++       case ENET: return "ENET";
++#endif
++#ifdef ENETDOWN
++       case ENETDOWN: return "network is down";
++#endif
++#ifdef ENETRESET
++       case ENETRESET: return "network dropped connection on reset";
++#endif
++#ifdef ENETUNREACH
++       case ENETUNREACH: return "network is unreachable";
++#endif
++#ifdef ENFILE
++       case ENFILE: return "file table overflow";
++#endif
++#ifdef ENOANO
++       case ENOANO: return "anode table overflow";
++#endif
++#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
++       case ENOBUFS: return "no buffer space available";
++#endif
++#ifdef ENOCSI
++       case ENOCSI: return "no CSI structure available";
++#endif
++#if defined(ENODATA) && (!defined(ECONNREFUSED) || (ENODATA != ECONNREFUSED))
++       case ENODATA: return "no data available";
++#endif
++#ifdef ENODEV
++       case ENODEV: return "no such device";
++#endif
++#ifdef ENOENT
++       case ENOENT: return "no such file or directory";
++#endif
++#ifdef ENOEXEC
++       case ENOEXEC: return "exec format error";
++#endif
++#ifdef ENOLCK
++       case ENOLCK: return "no locks available";
++#endif
++#ifdef ENOLINK
++       case ENOLINK: return "link has be severed";
++#endif
++#ifdef ENOMEM
++       case ENOMEM: return "not enough memory";
++#endif
++#ifdef ENOMSG
++       case ENOMSG: return "no message of desired type";
++#endif
++#ifdef ENONET
++       case ENONET: return "machine is not on the network";
++#endif
++#ifdef ENOPKG
++       case ENOPKG: return "package not installed";
++#endif
++#ifdef ENOPROTOOPT
++       case ENOPROTOOPT: return "bad proocol option";
++#endif
++#ifdef ENOSPC
++       case ENOSPC: return "no space left on device";
++#endif
++#if defined(ENOSR) && (!defined(ENAMETOOLONG) || (ENAMETOOLONG != ENOSR))
++       case ENOSR: return "out of stream resources";
++#endif
++#if defined(ENOSTR) && (!defined(ENOTTY) || (ENOTTY != ENOSTR))
++       case ENOSTR: return "not a stream device";
++#endif
++#ifdef ENOSYM
++       case ENOSYM: return "unresolved symbol name";
++#endif
++#ifdef ENOSYS
++       case ENOSYS: return "function not implemented";
++#endif
++#ifdef ENOTBLK
++       case ENOTBLK: return "block device required";
++#endif
++#ifdef ENOTCONN
++       case ENOTCONN: return "socket is not connected";
++#endif
++#ifdef ENOTDIR
++       case ENOTDIR: return "not a directory";
++#endif
++#if defined(ENOTEMPTY) && (!defined(EEXIST) || (ENOTEMPTY != EEXIST))
++       case ENOTEMPTY: return "directory not empty";
++#endif
++#ifdef ENOTNAM
++       case ENOTNAM: return "not a name file";
++#endif
++#ifdef ENOTSOCK
++       case ENOTSOCK: return "socket operation on non-socket";
++#endif
++#ifdef ENOTSUP
++       case ENOTSUP: return "operation not supported";
++#endif
++#ifdef ENOTTY
++       case ENOTTY: return "inappropriate device for ioctl";
++#endif
++#ifdef ENOTUNIQ
++       case ENOTUNIQ: return "name not unique on network";
++#endif
++#ifdef ENXIO
++       case ENXIO: return "no such device or address";
++#endif
++#if defined(EOPNOTSUPP) &&  (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP))
++       case EOPNOTSUPP: return "operation not supported on socket";
++#endif
++#ifdef EPERM
++       case EPERM: return "not owner";
++#endif
++#if defined(EPFNOSUPPORT) && (!defined(ENOLCK) || (ENOLCK != EPFNOSUPPORT))
++       case EPFNOSUPPORT: return "protocol family not supported";
++#endif
++#ifdef EPIPE
++       case EPIPE: return "broken pipe";
++#endif
++#ifdef EPROCLIM
++       case EPROCLIM: return "too many processes";
++#endif
++#ifdef EPROCUNAVAIL
++       case EPROCUNAVAIL: return "bad procedure for program";
++#endif
++#ifdef EPROGMISMATCH
++       case EPROGMISMATCH: return "program version wrong";
++#endif
++#ifdef EPROGUNAVAIL
++       case EPROGUNAVAIL: return "RPC program not available";
++#endif
++#ifdef EPROTO
++       case EPROTO: return "protocol error";
++#endif
++#ifdef EPROTONOSUPPORT
++       case EPROTONOSUPPORT: return "protocol not suppored";
++#endif
++#ifdef EPROTOTYPE
++       case EPROTOTYPE: return "protocol wrong type for socket";
++#endif
++#ifdef ERANGE
++       case ERANGE: return "math result unrepresentable";
++#endif
++#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
++       case EREFUSED: return "EREFUSED";
++#endif
++#ifdef EREMCHG
++       case EREMCHG: return "remote address changed";
++#endif
++#ifdef EREMDEV
++       case EREMDEV: return "remote device";
++#endif
++#ifdef EREMOTE
++       case EREMOTE: return "pathname hit remote file system";
++#endif
++#ifdef EREMOTEIO
++       case EREMOTEIO: return "remote i/o error";
++#endif
++#ifdef EREMOTERELEASE
++       case EREMOTERELEASE: return "EREMOTERELEASE";
++#endif
++#ifdef EROFS
++       case EROFS: return "read-only file system";
++#endif
++#ifdef ERPCMISMATCH
++       case ERPCMISMATCH: return "RPC version is wrong";
++#endif
++#ifdef ERREMOTE
++       case ERREMOTE: return "object is remote";
++#endif
++#ifdef ESHUTDOWN
++       case ESHUTDOWN: return "can't send afer socket shutdown";
++#endif
++#ifdef ESOCKTNOSUPPORT
++       case ESOCKTNOSUPPORT: return "socket type not supported";
++#endif
++#ifdef ESPIPE
++       case ESPIPE: return "invalid seek";
++#endif
++#ifdef ESRCH
++       case ESRCH: return "no such process";
++#endif
++#ifdef ESRMNT
++       case ESRMNT: return "srmount error";
++#endif
++#ifdef ESTALE
++       case ESTALE: return "stale remote file handle";
++#endif
++#ifdef ESUCCESS
++       case ESUCCESS: return "Error 0";
++#endif
++#if defined(ETIME) && (!defined(ELOOP) || (ETIME != ELOOP))
++       case ETIME: return "timer expired";
++#endif
++#if defined(ETIMEDOUT) && (!defined(ENOSTR) || (ETIMEDOUT != ENOSTR))
++       case ETIMEDOUT: return "connection timed out";
++#endif
++#ifdef ETOOMANYREFS
++       case ETOOMANYREFS: return "too many references: can't splice";
++#endif
++#ifdef ETXTBSY
++       case ETXTBSY: return "text file or pseudo-device busy";
++#endif
++#ifdef EUCLEAN
++       case EUCLEAN: return "structure needs cleaning";
++#endif
++#ifdef EUNATCH
++       case EUNATCH: return "protocol driver not attached";
++#endif
++#ifdef EUSERS
++       case EUSERS: return "too many users";
++#endif
++#ifdef EVERSION
++       case EVERSION: return "version mismatch";
++#endif
++#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
++       case EWOULDBLOCK: return "operation would block";
++#endif
++#ifdef EXDEV
++       case EXDEV: return "cross-domain link";
++#endif
++#ifdef EXFULL
++       case EXFULL: return "message tables full";
++#endif
++       default:
++#ifdef NO_STRERROR
++           return "unknown POSIX error";
++#else
++           return strerror(errno);
++#endif
++    }
++}
++
++/*
++ * end of excerpt from tcl8.0.X/generic/tclPosixStr.c
++ */
++
++/*
+  * stolen from exp_log.c - this function is called from the Expect library
+  * but the one that the library supplies calls Tcl functions.  So we supply
+  * our own.
+diff -up expect5.45/expect.h.orig expect5.45/expect.h
+--- expect5.45/expect.h.orig	2010-09-01 00:20:27.000000000 +0200
++++ expect5.45/expect.h	2015-05-19 12:00:58.674248152 +0200
+@@ -258,6 +258,46 @@ typedef long LONG;
+ typedef struct Tcl_RegExp_ *Tcl_RegExp;
  
- 	/* Allocate space. */
--	r = (regexp *)ckalloc(sizeof(regexp) + (unsigned)rcstate->regsize);
-+	r = (regexp *)malloc(sizeof(regexp) + (unsigned)rcstate->regsize);
- 	if (r == NULL)
- 		FAIL("out of space");
+ /*
++ * The following declarations either map ckalloc and ckfree to
++ * malloc and free, or they map them to procedures with all sorts
++ * of debugging hooks defined in tclCkalloc.c.
++ */
++
++#ifdef TCL_MEM_DEBUG
++
++#  define Tcl_Alloc(x) Tcl_DbCkalloc(x, __FILE__, __LINE__)
++#  define Tcl_Free(x)  Tcl_DbCkfree(x, __FILE__, __LINE__)
++#  define Tcl_Realloc(x,y) Tcl_DbCkrealloc((x), (y),__FILE__, __LINE__)
++#  define ckalloc(x) Tcl_DbCkalloc(x, __FILE__, __LINE__)
++#  define ckfree(x)  Tcl_DbCkfree(x, __FILE__, __LINE__)
++#  define ckrealloc(x,y) Tcl_DbCkrealloc((x), (y),__FILE__, __LINE__)
++
++#else
++
++/*
++ * If USE_TCLALLOC is true, then we need to call Tcl_Alloc instead of
++ * the native malloc/free.  The only time USE_TCLALLOC should not be
++ * true is when compiling the Tcl/Tk libraries on Unix systems.  In this
++ * case we can safely call the native malloc/free directly as a performance
++ * optimization.
++ */
++
++#  if USE_TCLALLOC
++#     define ckalloc(x) Tcl_Alloc(x)
++#     define ckfree(x) Tcl_Free(x)
++#     define ckrealloc(x,y) Tcl_Realloc(x,y)
++#  else
++#     define ckalloc(x) malloc(x)
++#     define ckfree(x)  free(x)
++#     define ckrealloc(x,y) realloc(x,y)
++#  endif
++#  define Tcl_DumpActiveMemory(x)
++#  define Tcl_ValidateAllMemory(x,y)
++
++#endif /* !TCL_MEM_DEBUG */
++
++
++/*
+  * These function have been renamed. The old names are deprecated, but we
+  * define these macros for backwards compatibilty.
+  */
+@@ -268,6 +308,14 @@ typedef struct Tcl_RegExp_ *Tcl_RegExp;
+ #define Tcl_Return Tcl_SetResult
+ #define Tcl_TildeSubst Tcl_TranslateFileName
  
-@@ -399,7 +399,7 @@
- 	rcstate->regcode = r->program;
- 	regc(MAGIC, rcstate);
- 	if (reg(0, &flags, rcstate) == NULL) {
--	  ckfree ((char*) r);
-+	  free ((char*) r);
- 	  return(NULL);
- 	}
++/*
++ * In later releases, Tcl_Panic will be the correct name to use.  For now
++ * we leave it as panic to avoid breaking existing binaries.
++ */
++
++#define Tcl_Panic panic
++#define Tcl_PanicVA panicVA
++
+ #endif /* RESOURCE_INCLUDED */
  
+ #undef TCL_STORAGE_CLASS
diff --git a/expect.spec b/expect.spec
index 8ce234a..ba110c0 100644
--- a/expect.spec
+++ b/expect.spec
@@ -5,7 +5,7 @@
 Summary: A program-script interaction and testing utility
 Name: expect
 Version: %{majorver}
-Release: 18%{?dist}
+Release: 19%{?dist}
 License: Public Domain
 Group: Development/Languages
 # URL: probably more useful is http://sourceforge.net/projects/expect/
@@ -180,6 +180,10 @@ rm -rf "$RPM_BUILD_ROOT"
 %{_mandir}/man1/tknewsbiff.1*
 
 %changelog
+* Wed May 20 2015 Vitezslav Crhonek <vcrhonek at redhat.com> - 5.45-19
+- Use different and probably better approach of fixing segfaults if Tcl is
+  built with stubs and Expect is used directly from C program
+
 * Tue Sep 09 2014 Vitezslav Crhonek <vcrhonek at redhat.com> - 5.45-18
 - Fix leaked fd (patch by Matej Mužila)
   Resolves: #1001220
-- 
cgit v0.10.2


	http://pkgs.fedoraproject.org/cgit/expect.git/commit/?h=master&id=9a7965843e92b2b41a15377168ea5b5c498db5c9


More information about the scm-commits mailing list