develooper Front page | perl.perl5.porters | Postings from May 2015

(perlio uses undocumented libc structs) Re: FILE structure internalsissue building blead on WindowswithVisualStudio 2015 RC

Thread Previous | Thread Next
From:
bulk88
Date:
May 5, 2015 10:17
Subject:
(perlio uses undocumented libc structs) Re: FILE structure internalsissue building blead on WindowswithVisualStudio 2015 RC
Message ID:
BLU436-SMTP496DAE8976D1FBF416C612DFD10@phx.gbl
bulk88 wrote:
> The FILE struct issue I will address later today. I am researching what 
> MS changed for VC 2015 specifically and if its ISO C compliant.

vc 2013
_______________________________________________________________________
/***
*stdio.h - definitions/declarations for standard I/O routines
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
*       This file defines the structures, values, macros, and functions
*       used by the level 2 I/O ("standard I/O") routines.
*       [ANSI/System V]
*
*       [Public]
*
****/

#pragma once

#ifndef _INC_STDIO
#define _INC_STDIO

#include <crtdefs.h>

/*
  * Currently, all MS C compilers for Win32 platforms default to 8 byte
  * alignment.
  */
#pragma pack(push,_CRT_PACKING)

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */


/* Buffered I/O macros */

#define BUFSIZ  512

#ifdef _CRTBLD
/*
  * Real default size for stdio buffers
  */
#define _INTERNAL_BUFSIZ    4096
#define _SMALL_BUFSIZ       512
#endif  /* _CRTBLD */

/*
  * Default number of supported streams. _NFILE is confusing and 
obsolete, but
  * supported anyway for backwards compatibility.
  */
#define _NFILE      _NSTREAM_

#define _NSTREAM_   512

/*
  * Number of entries in _iob[] (declared below). Note that _NSTREAM_ 
must be
  * greater than or equal to _IOB_ENTRIES.
  */
#define _IOB_ENTRIES 20

#define EOF     (-1)


#ifndef _FILE_DEFINED
struct _iobuf {
         char *_ptr;
         int   _cnt;
         char *_base;
         int   _flag;
         int   _file;
         int   _charbuf;
         int   _bufsiz;
         char *_tmpfname;
         };
typedef struct _iobuf FILE;
#define _FILE_DEFINED
#endif  /* _FILE_DEFINED */


/* Directory where temporary files may be created. */

#define _P_tmpdir   "\\"
#define _wP_tmpdir  L"\\"

/* L_tmpnam = length of string _P_tmpdir
  *            + 1 if _P_tmpdir does not end in "/" or "\", else 0
  *            + 12 (for the filename string)
  *            + 1 (for the null terminator)
  * L_tmpnam_s = length of string _P_tmpdir
  *            + 1 if _P_tmpdir does not end in "/" or "\", else 0
  *            + 16 (for the filename string)
  *            + 1 (for the null terminator)
  */
#define L_tmpnam   (sizeof(_P_tmpdir) + 12)
#if __STDC_WANT_SECURE_LIB__
#define L_tmpnam_s (sizeof(_P_tmpdir) + 16)
#endif  /* __STDC_WANT_SECURE_LIB__ */



/* Seek method constants */

#define SEEK_CUR    1
#define SEEK_END    2
#define SEEK_SET    0

_______________________________________________________________________


vc 2015
_______________________________________________________________________
//
// corecrt_wstdio.h
//
//      Copyright (c) Microsoft Corporation. All rights reserved.
//
// This file declares the wide character (wchar_t) I/O functionality, 
shared by
// <stdio.h> and <wchar.h>.  It also defines several core I/O types, 
which are
// also shared by those two headers.
//
#pragma once

#include <corecrt.h>
#include <corecrt_stdio_config.h>

_CRT_BEGIN_C_HEADER


//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Stream I/O Declarations Required by this Header
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#ifndef _FILE_DEFINED
     #define _FILE_DEFINED
     typedef struct _iobuf
     {
         void* _Placeholder;
     } FILE;
#endif
_______________________________________________________________________

//
// stdio.h
//
//      Copyright (c) Microsoft Corporation. All rights reserved.
//
// The C Standard Library <stdio.h> header.
//
#pragma once
#define _INC_STDIO

#include <corecrt.h>
#include <corecrt_wstdio.h>

_CRT_BEGIN_C_HEADER

/* Buffered I/O macros */

#define BUFSIZ  512



/*
  * Default number of supported streams. _NFILE is confusing and 
obsolete, but
  * supported anyway for backwards compatibility.
  */
#define _NFILE      _NSTREAM_

#define _NSTREAM_   512

/*
  * Number of entries in _iob[] (declared below). Note that _NSTREAM_ 
must be
  * greater than or equal to _IOB_ENTRIES.
  */
#define _IOB_ENTRIES 3

#define EOF    (-1)

#define _IOFBF 0x0000
#define _IOLBF 0x0040
#define _IONBF 0x0004



#define L_tmpnam   260 // _MAX_PATH
#if __STDC_WANT_SECURE_LIB__
     #define L_tmpnam_s L_tmpnam
#endif



/* Seek method constants */

#define SEEK_CUR    1
#define SEEK_END    2
#define SEEK_SET    0
_______________________________________________________________________


as per http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf (C99 
spec?) section 7.19.1

_______________________________________________________________________
2 The types declared are size_t (described in 7.17); FILE which is an 
object type capable of recording all the information needed to control a 
stream, including its file position indicator, a pointer to its 
associated buffer (if any), an error indicator that records whether a 
read/write error has occurred, and an end-of-file indicator that records 
whether the end of the file has been reached;
_______________________________________________________________________

There is no requirement as to the members or their names of a FILE *.

So is Perl at fault for using undocumented libc members, or is MS at 
fault for breaking decades of back compat? Here is the first function 
that fails to compile

_______________________________________________________________________
static int
PerlIOStdio_invalidate_fileno(pTHX_ FILE *f)
{
     PERL_UNUSED_CONTEXT;

     /* XXX this could use PerlIO_canset_fileno() and
      * PerlIO_set_fileno() support from Configure
      */
#  if defined(__UCLIBC__)
     /* uClibc must come before glibc because it defines __GLIBC__ as 
well. */
     f->__filedes = -1;
     return 1;
#  elif defined(__GLIBC__)
     /* There may be a better way for GLIBC:
     	- libio.h defines a flag to not close() on cleanup
      */	
     f->_fileno = -1;
     return 1;
#  elif defined(__sun)
     PERL_UNUSED_ARG(f);
     return 0;
#  elif defined(__hpux)
     f->__fileH = 0xff;
     f->__fileL = 0xff;
     return 1;
    /* Next one ->_file seems to be a reasonable fallback, i.e. if
       your platform does not have special entry try this one.
       [For OSF only have confirmation for Tru64 (alpha)
       but assume other OSFs will be similar.]
     */
#  elif defined(_AIX) || defined(__osf__) || defined(__irix__)
     f->_file = -1;
     return 1;
#  elif defined(__FreeBSD__)
     /* There may be a better way on FreeBSD:
         - we could insert a dummy func in the _close function entry
	f->_close = (int (*)(void *)) dummy_close;
      */
     f->_file = -1;
     return 1;
#  elif defined(__OpenBSD__)
     /* There may be a better way on OpenBSD:
         - we could insert a dummy func in the _close function entry
	f->_close = (int (*)(void *)) dummy_close;
      */
     f->_file = -1;
     return 1;
#  elif defined(__EMX__)
     /* f->_flags &= ~_IOOPEN; */	/* Will leak stream->_buffer */
     f->_handle = -1;
     return 1;
#  elif defined(__CYGWIN__)
     /* There may be a better way on CYGWIN:
         - we could insert a dummy func in the _close function entry
	f->_close = (int (*)(void *)) dummy_close;
      */
     f->_file = -1;
     return 1;
#  elif defined(WIN32)
#    if defined(UNDER_CE)
     /* WIN_CE does not have access to FILE internals, it hardly has FILE
        structure at all
      */
#    else
     f->_file = -1;
#    endif
     return 1;
#  else
#if 0
     /* Sarathy's code did this - we fall back to a dup/dup2 hack
        (which isn't thread safe) instead
      */
#    error "Don't know how to set FILE.fileno on your platform"
#endif
     PERL_UNUSED_ARG(f);
     return 0;
#  endif
}
_______________________________________________________________________


Some quotes from universal CRT source code.
_______________________________________________________________________
// Ensure that __crt_stdio_stream_data* and FILE* pointers are freely 
convertible:
static_assert(
     offsetof(__crt_stdio_stream_data, _public_file) == 0,
     "FILE member of __crt_stdio_stream_data is not at offset zero."
     );

static_assert(
     sizeof(FILE) == sizeof(void*),
     "FILE structure has unexpected size."
     );
_______________________________________________________________________
extern "C" size_t __cdecl _fread_nolock_s(
     void*  const buffer,
     size_t const buffer_size,
     size_t const element_size,
     size_t const element_count,
     FILE*  const public_stream
     )
{
     __crt_stdio_stream const stream(public_stream);

     if (element_size == 0 || element_count == 0)
         return 0;

     _VALIDATE_RETURN(buffer != nullptr, EINVAL, 0);
     if (!stream.valid() || element_count > (SIZE_MAX / element_size))
     {
_______________________________________________________________________
class __crt_stdio_stream
{
public:

     __crt_stdio_stream() throw()
         : _stream(nullptr)
     {
     }

     explicit __crt_stdio_stream(FILE* const stream) throw()
         : _stream(reinterpret_cast<__crt_stdio_stream_data*>(stream))
     {
     }
_______________________________________________________________________
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Internal Stream Types (__crt_stdio_stream and friends)
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
struct __crt_stdio_stream_data
{
     union
     {
         FILE  _public_file;
         char* _ptr;
     };

     char*            _base;
     int              _cnt;
     long             _flags;
     long             _file;
     int              _charbuf;
     int              _bufsiz;
     char*            _tmpfname;
     CRITICAL_SECTION _lock;
};
_______________________________________________________________________

So a FILE * is now a C++ object (probably based on the above if my C++ 
knowledge is good enough), hence it is opaque. Now what? file a MS bug 
report? Or is perl going to require a C++ shim .o file and #include 
non-public corecrt_internal_stdio.h to access those members?

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About