Copying files content in C - c

int copy( char *from, char *to ) {
int fd_from, fd_to, rbytes, wbytes;
char buff[256];
if( ( fd_from = open( from, O_RDONLY ) ) == -1 )
{ perror( “open from” ); return( - 1 ); }
if( ( fd_to = open( to, O_WRONLY | O_CREAT, 0664 ) ) == -1 )
{ perror( “open to” ); return( -1 ); }
if( ( rbytes = read( fd_from, buff, 256 ) ) == -1 )
{ perror( “read 1” ); return( -1 ); }
while( rbytes > 0 ) {
if( ( wbytes = write( fd_to, buff, rbytes ) ) == -1 )
{ perror( “write” ); return( -1 ); }
if( wbytes != rbytes )
{ fprintf( stderr, “bad write\n” ); return( -1 ); }
if( ( rbytes = read( fd_from, buff, 256 ) ) == -1 )
{ perror( “read 2” ); return( -1 ); }
}
close( fd_from ); close( fd_to ); return( 0 );
}
why is there a loop that checks if rbytes>0?
I understand the reasons for 2 if's statments inside the loop but not the last one, why do we have to read the file again?

why is there a loop that checks if rbytes>0?
Because every read operation only reads up to 256 bytes, yet most files are larger than that. The loop continues until the input file is fully read, at which point read will return 0, and the loop will terminate.

Related

Blocking Client connection from the Server side, when User types one of the arrow keys

I need to block a connection from the Server side, based on users who type up/down/left/right arrow on the Client side.
I tried one of the following, but it does not work:
strcmp( userName, "^[[A" ) == 0
I created a socket server which checks a connection for an valid nickname, but when the client types one of the arrows:
up arrow = ^[[A
down arrow = ^[[B
left arrow = ^[[D
right arrow = ^[[C
On the server side is just ignored and it does not close the client.
Here is a program which illustrate the problem:
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8888
#define MSGLEN 256
#define MAXNAMELENGTH 25
int server_socket = 0;
int client_socket = 0;
struct sockaddr_in address;
void create_sckt ( void );
void bind_sckt ( const size_t server_len );
void listen_sckt ( void );
void accept_sckt ( size_t server_len );
ssize_t recv_sckt ( char *const userName );
void send_msg ( const int userID, const char *const userName );
int main( void )
{
size_t server_len = sizeof( address );
char userName[ MSGLEN + 1 ] = { 0 };
const char *const wrong_name = "[+]Please type a Valide Name and come back.\n";
create_sckt ();
bind_sckt ( server_len );
listen_sckt ();
printf( "Starting Server...\n" );
while ( 1 )
{
accept_sckt( server_len );
memset( userName, '\0', sizeof(userName ) );
recv_sckt( userName );
userName[ strcspn( userName, "\n" ) ] = 0;
if ( strcmp( userName, "^[[A" ) == 0 && strlen( userName ) > MAXNAMELENGTH )
{
send_msg ( client_socket, wrong_name );
close( client_socket );
break;
}else
{
char welcome_msg[1024] = { 0 };
sprintf( welcome_msg, " Welcome %s\n", userName );
send_msg ( client_socket, welcome_msg );
}
}
close( server_socket );
}
void create_sckt ( void )
{
server_socket = socket( AF_INET, SOCK_STREAM, 0 );
if ( server_socket == -1 )
{
printf("socket() failed\n");
fprintf(stderr, "%s %d\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
}
void listen_sckt ( void )
{
int ret = listen( server_socket, 3 );
if ( ret == -1 )
{
printf ( "listen() failed\n" );
fprintf( stderr, "%s %d\n", strerror( errno ), errno );
exit ( EXIT_FAILURE );
}
}
void bind_sckt ( const size_t server_len )
{
int ret = bind( server_socket, ( struct sockaddr* )&address, ( socklen_t )server_len );
if ( ret == -1 )
{
printf ( "bind() failed\n" );
fprintf( stderr, "%s %d\n", strerror( errno ), errno);
exit ( EXIT_FAILURE );
}
}
void accept_sckt ( size_t server_len )
{
client_socket = accept( server_socket, (struct sockaddr *)&address, (socklen_t*)&server_len );
if ( client_socket == -1 )
{
printf ( "accept() failed\n" );
fprintf( stderr, "%s %d\n", strerror(errno), errno );
exit ( EXIT_FAILURE );
}
}
void send_msg ( const int userID, const char *const userName )
{
ssize_t ret = send( userID , userName , strlen( userName ) , 0 );
if ( ret == -1 )
{
printf ( "recv() failed\n" );
fprintf( stderr, "%s %d\n", strerror( errno ), errno );
exit ( EXIT_FAILURE );
}else
{
printf( "Hello message sent\n" );
}
}
ssize_t recv_sckt ( char *const userName )
{
ssize_t ret = recv( client_socket, userName, MSGLEN, 0);
if ( ret == -1 )
{
printf ( "recv() failed\n" );
fprintf( stderr, "%s %d\n", strerror( errno ), errno );
exit ( EXIT_FAILURE );
}
return ret;
}
How should I block the connection, when on the client side are used one of the arrow keys?
On the client side it prints (welcome ):
Please enter your name: ^[[A
Connect to Server: 192.168.0.103:8888
You are: 192.168.0.103:42074
Welcome
After I tried examples which was provided in the above Answer and also in one comment and did not work. I found a solution to my problem.
GCC seems to allow \e but it is not standard:
error: non-ISO-standard escape sequence, '\e'|
Tryed also with "\x27[A" and still no working.
The only thing which worked in this case is 0x1B:
if ( userName[0] == 0x1B )
Because the first two characters ^[ represent a single escape character. Try comparing to string "\e[A" instead. And change the logical operator from && to ||. You want to fail if it's an arrow or it's too long.

Extract resources from sys-file

How to extract resources for sys-file? I believe that exe, dll and sys-files have same headers. Is that correct?
I don't understand what shall I do with VirtualAddress and Size which I get for resource table.
#include <stdio.h>
#include <windows.h>
#include <string.h>
void main()
{
FILE *file = fopen( "example.sys", "r" );
IMAGE_DOS_HEADER dos_header;
IMAGE_NT_HEADERS nt_header;
IMAGE_DATA_DIRECTORY data_directory;
char *data;
if( file != NULL )
{
fseek( file, 0, SEEK_SET );
fread( &dos_header, sizeof( dos_header ), 1, file );
if( dos_header.e_magic != IMAGE_DOS_SIGNATURE )
return;
fseek( file, dos_header.e_lfanew, SEEK_SET );
fread( &nt_header, sizeof( nt_header ), 1, file );
if( nt_header.Signature != IMAGE_NT_SIGNATURE )
return;
data_directory = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
data = malloc( data_directory.Size + 1 );
memset( data, 0, data_directory.Size + 1 );
fseek( file, data_directory.VirtualAddress, SEEK_SET ); // <- ????
fread( data, data_directory.Size, 1, file );
free( data );
fclose( file );
}
}
VirtualAddress is actually the relative virtual address (RVA) of the data structure.
For example, if this structure is for import symbols, this field contains the RVA of the IMAGE_IMPORT_DESCRIPTOR array.
isize contains the size in bytes of the data structure referred to by VirtualAddress.
Take a look at THIS link. It is a good explanation on how to go deep into a win32 assembly.
I finally found code example which answered my question - PEDump.
Using it I made this sample:
#include <stdio.h>
#include <windows.h>
#include <string.h>
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (DWORD)(addValue))
#define RESOURCE_ADDRESS( pdr, o ) ((PUCHAR) (pdr + 1) + (o))
typedef struct tag_VS_VERSIONINFO
{
USHORT wLength; // 00 length of entire version resource
USHORT wValueLength; // 02 length of fixed file info, if any
USHORT wType; // 04 type of resource (1 = text, 0 = binary)
WCHAR szKey[17]; // 06 key -- VS_VERSION_INFO + padding byte
VS_FIXEDFILEINFO Value; // 28 fixed information about this file (13 dwords)
}
VS_VERSIONINFO, *PVS_VERSIONINFO; // 5C
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva,
PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
// Is the RVA within this section?
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
return section;
}
return 0;
}
LPVOID GetPtrFromRVA( DWORD rva, PIMAGE_NT_HEADERS pNTHeader, DWORD imageBase )
{
PIMAGE_SECTION_HEADER pSectionHdr;
INT delta;
pSectionHdr = GetEnclosingSectionHeader( rva, pNTHeader );
if ( !pSectionHdr )
return 0;
delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
return (PVOID) ( imageBase + rva - delta );
}
void main()
{
unsigned int index;
PIMAGE_DOS_HEADER dos_header;
PIMAGE_NT_HEADERS nt_header;
PIMAGE_DATA_DIRECTORY data_directory;
PIMAGE_RESOURCE_DIRECTORY resources;
PIMAGE_RESOURCE_DIRECTORY_ENTRY listItem;
PIMAGE_RESOURCE_DIRECTORY child;
PIMAGE_RESOURCE_DIRECTORY_ENTRY version;
PIMAGE_RESOURCE_DATA_ENTRY data_entry;
PVS_VERSIONINFO version_info;
HANDLE hFile;
HANDLE hFileMapping;
LPVOID lpFileBase;
hFile = CreateFile( L"samples.sys",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
);
if ( hFile == INVALID_HANDLE_VALUE )
return;
hFileMapping = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
if ( hFileMapping == 0 )
{
CloseHandle(hFile);
return;
}
lpFileBase = MapViewOfFile( hFileMapping, FILE_MAP_READ, 0, 0, 0 );
if ( lpFileBase == 0 )
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
return;
}
dos_header = MakePtr( PIMAGE_DOS_HEADER, lpFileBase, 0 );
if( dos_header->e_magic != IMAGE_DOS_SIGNATURE )
return;
nt_header = MakePtr( PIMAGE_NT_HEADERS, lpFileBase, dos_header->e_lfanew );
if( nt_header->Signature != IMAGE_NT_SIGNATURE )
return;
data_directory = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
resources = ( PIMAGE_RESOURCE_DIRECTORY )GetPtrFromRVA( data_directory->VirtualAddress, nt_header, ( DWORD )lpFileBase );
listItem = ( PIMAGE_RESOURCE_DIRECTORY_ENTRY )( resources + 1 );
for( index = 0; index < resources->NumberOfIdEntries; index++ )
{
if( listItem->Id == ( WORD )RT_VERSION )
{
if( listItem->DataIsDirectory )
{
child = ( PIMAGE_RESOURCE_DIRECTORY )( ( listItem->OffsetToData & 0x7FFFFFFF ) + (DWORD)resources );
version = ( PIMAGE_RESOURCE_DIRECTORY_ENTRY )( child + 1 );
if( version->DataIsDirectory )
{
child = ( PIMAGE_RESOURCE_DIRECTORY )( ( version->OffsetToData & 0x7FFFFFFF ) + (DWORD)resources );
version = ( PIMAGE_RESOURCE_DIRECTORY_ENTRY )( child + 1 );
data_entry = ( PIMAGE_RESOURCE_DATA_ENTRY )( ( version->OffsetToData & 0x7FFFFFFF ) + (DWORD)resources );
version_info = ( PVS_VERSIONINFO )GetPtrFromRVA( data_entry->OffsetToData, nt_header, ( DWORD )lpFileBase );
}
}
}
listItem += 1;
}
}
Most interesting part here is function GetPtrFromRVA which shall be used to convert VirtualAddress to offset from the beginning of the file.

CryptEncrypt ignores HASH?

I am trying to make an application which uses AES 256 Encryption. Unfortunately i can't get it work. Maybe i didn't understand the crpytographic logic fully.
So it is working, but as far as i understand the hash contains the password. But if i change the password the output is the same. So it seems that CryptEncrypt ignoes the Hash.
Could someone please help me?
Thanks in advance!
Here is my code:
if ( !CryptAcquireContext( &hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT ) )
{
printf( "\nCryptAcquireContext failed %d", GetLastError() );
return;
}
if ( !CryptImportKey( hProv, ( const LPBYTE )&keyBlob, sizeof( keyBlob ), 0, CRYPT_EXPORTABLE, &hPubKey ) )
{
printf( "\nCryptImportKey failed %d", GetLastError() );
return;
}
if ( !CryptCreateHash( hProv, CALG_SHA_256, 0, 0, &hHash ) )
{
printf( "Error %x during CryptCreateHash!\n", GetLastError() );
return;
}
if ( !CryptHashData( hHash, ( PBYTE )wszPassword, cbPassword, 0 ) )
{
printf( "Error %x during CryptHashData!\n", GetLastError() );
return;
}
//if ( !CryptDeriveKey( hProv, CALG_AES_256, hHash, CRYPT_EXPORTABLE, &hKey ) )//hKey
//{
// printf( "Error %x during CryptDeriveKey!\n", GetLastError() );
// return;
//}
if ( !CryptSetKeyParam( hPubKey, KP_IV, ivData, 0 ) )
{
printf( "\nCryptSetKeyParam failed %d", GetLastError() );
return;
}
DWORD size = ( DWORD )strlen( StringToEncrypt ) / sizeof( char );
//printf( "\nLength of string to encrypt = %d\n\n", size );
if ( !CryptEncrypt( hPubKey, hHash, TRUE, 0, ( LPBYTE )StringToEncrypt, &size, ( size / 16 + 1 ) * 16 ) )
{
printf( "\nCryptEncrypt failed %d", GetLastError() );
int a = GetLastError();
switch ( a )
{
case NTE_BAD_HASH_STATE: printf( "NTE_BAD_HASH_STATE" ); break;
case NTE_BAD_HASH: printf( "NTE_BAD_HASH" ); break;
}
return;
}
The "password" - usually known as the key - is in hPubKey. The hHash is for generating a hash at the same time as the encryption is done. Look here for more information.

client receives weird characters from server, original message is not present at all

I have a normal client-server communication, just like Beej's guide insructs to do this stuff.
Server sends a string, but at recv in client, although value returned is ok (i.e. equal to the no of bytes sent from server), the characters received are totally weird, and value returned by strlen on received string is smaller than value returned by recv.
It seems really weird to me, so if you could give me a hint, it would be great.
This is part of server's code:
s_gateway_server = socket( PF_INET, SOCK_STREAM, 0 );
memset( &server, 0, sizeof( server ) ); // asiguram padding-ul
server.sin_family = AF_INET;
server.sin_port = htons( is.port );
inet_pton( AF_INET, is.ip, &server.sin_addr );
status = connect( s_gateway_server, ( struct sockaddr* ) &server, sizeof( server ) );
if( status == -1 )
{
printf( "ERROR\nNu te-ai putut conecta la server-ul %s :-(\n", is.ip );
goto exit;
}
l = strlen( msg ) + 1;
status = send( s_gateway_server, &msg, l, 0 );
if( status == -1 )
{
perror( "ERROR\nla send catre server" );
goto exit;
}
if( status < l )
{
//TODO trimite restul de pachet
printf( "ERROR\npachet ajuns incomplet la server\n" );
goto exit;
}
printf( "Am trimis %d octeti: %s\n", status, msg );
And this is part of client's code:
void send_and_receive( int sock )
{
int status, ret;
while( 1 )
{
char receivebuff[500];
status = recv( sock, &receivebuff, 500, 0 );
if( status == -1 )
{
perror( "ERROR\nla recv" );
continue;
}
if( status == 0 )
// connection closed
break;
(did not paste all the function), and the function is called in main():
int main( int argc, char **argv )
{
int s_server_gateway, conn_s_server_gateway, ret;
struct sockaddr_in gateway;
socklen_t length;
ret = parse_arg(argc, argv);
if( ret )
return 1;
s_server_gateway = listen_to_clients();
if( s_server_gateway < 0 )
return 2;
while( 1 )
{
length = sizeof( gateway );
conn_s_server_gateway = accept( s_server_gateway, ( struct sockaddr * ) &gateway, &length );
if( conn_s_server_gateway == -1 )
{
perror( "ERROR\nla accept de la gateway" );
continue;
}
if( !fork() )
{
close( s_server_gateway );
send_and_receive( conn_s_server_gateway );
return 0;
}
else
{
close( conn_s_server_gateway );
continue;
}
}
close( s_server_gateway );
return 0;
}
int listen_to_clients()
{
int s_server_gateway, optval, ret;
struct sockaddr_in server;
s_server_gateway = socket( PF_INET, SOCK_STREAM, 0 );
if( s_server_gateway == -1 )
{
perror( "ERROR\nla deschidere socket" );
return -1;
}
memset( &server, 0, sizeof( server ) ); // asiguram padding-ul
server.sin_family = AF_INET;
server.sin_port = htons( port );
inet_pton( AF_INET, "127.0.0.1", &server.sin_addr );
optval = 1;
ret = setsockopt( s_server_gateway, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( int ) );
if( ret == -1 )
{
perror( "ERROR\nla setsockopt" );
close( s_server_gateway );
return -2;
}
ret = bind( s_server_gateway, ( struct sockaddr * ) &server, sizeof( server ) );
if( ret == -1 )
{
perror( "ERROR\nla bind" );
close( s_server_gateway );
return -3;
}
listen( s_server_gateway, BACKLOG );
if( ret == -1 )
{
perror( "ERROR\nla listen" );
close( s_server_gateway );
return -4;
}
return s_server_gateway;
}
Improper parameter to recv()
char receivebuff[500];
// status = recv( sock, &receivebuff, 500, 0 )
status = recv( sock, receivebuff, 500, 0 ); // no &
// or better
status = recv( sock, receivebuff, sizeof(receivebuff), 0 );

perlembed/perlcall example unbounded memory growth - valgrind says no leaks possible

all. I've been banging my head up against this one for a while... I'm trying to put together an example of basically perlembed + perlcall and more or less "borrowed" it from evpsgi. The problem is that it grows about 1MB in size for every 1000 iterations. This isn't the greatest situation to be in when running in a long lived process (which is the use case that I'm working with).
As the title states, if I run with valgrind it reports that there are no leaks possible. I ran with --trace-malloc=yes and it appears that free is only ever called at the end in a big batch of calls. I understand that this may be perl's MO but it would be nice if it at least re-used the memory and didn't grow until the OS killed off the process.
The entry for sv_2mortal mentions something about the buffer being available to be "stolen" but I've peppered the code with calls to sv_2mortal but there was no change.
Without further ado, here is the code. Please forgive the cargo cultishness of it. Thanks in advance!
/*
*
* cc `perl -MExtUtils::Embed -e ccopts -e ldopts` -Wall -ggdb test_perl_2.c -o test_perl_2
*
* # test.psgi
* use strict;
* use warnings;
* my $app = sub {
* return [ 200, [ test => 1 ], [ sprintf( "%d: Hello!!! from %s\n", $$, __FILE__ ) ] ];
* };
*
*/
#include <stdio.h>
#include <EXTERN.h> /* from the Perl distribution */
#include <perl.h> /* from the Perl distribution */
static PerlInterpreter *perlinterp; /*** The Perl interpreter ***/
static SV *app;
void do_stuff( void );
SV * get_stuff( void );
SV * call_stuff( SV * );
EXTERN_C void xs_init( pTHX );
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
EXTERN_C void xs_init( pTHX ) {
char *file = __FILE__;
dXSUB_SYS;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
}
int main( int argc, char **argv, char **env ) {
char code[ 1024 ];
char psgi[] = "test.psgi";
char *embedding[] = { "", "-e", "0" };
PERL_SYS_INIT3( &argc, &argv, &env );
perlinterp = perl_alloc();
PERL_SET_CONTEXT( perlinterp );
perl_construct( perlinterp );
perl_parse( perlinterp, xs_init, 3, embedding, (char **)NULL );
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
sprintf( code, "do '%s' or die $#", psgi );
app = eval_pv( code, TRUE ); /* croak_on_error */
do_stuff();
PL_perl_destruct_level = 1;
perl_destruct( perlinterp );
perl_free( perlinterp );
PERL_SYS_TERM();
return 0;
}
void do_stuff( void ) {
int body_lastindex, i, count;
AV *response_av, *body_av;
SV *stuff_sv, *response_sv, *status, *tmp_body_sv, *body_sv;
// count = 10000;
count = 10;
while( count-- ) {
ENTER;
SAVETMPS;
stuff_sv = get_stuff();
response_sv = call_stuff( stuff_sv );
if(
NULL == response_sv ||
! SvROK( response_sv ) ||
SvTYPE( SvRV( response_sv ) ) != SVt_PVAV
) {
printf( "NULL == response_sv\n" );
goto CLIENT_END;
}
response_av = (AV *)SvRV( response_sv );
status = *av_fetch( response_av, 0, 0 );
printf( "status = %ld\n", (long)SvIV( status ) );
body_av = (AV *)SvRV( *av_fetch( response_av, 2, 0 ) );
body_sv = newSV( 0 );
body_lastindex = av_len( body_av );
for( i = 0; i <= body_lastindex; i++ ) {
tmp_body_sv = (SV *)*av_fetch( body_av, i, 0 );
if( SvOK( tmp_body_sv ) ) {
sv_catsv( body_sv, tmp_body_sv );
}
}
printf( "body_sv = %s\n", SvPV_nolen( body_sv ) );
CLIENT_END:
FREETMPS;
LEAVE;
}
}
SV * get_stuff( void ) {
HV *stuff_hv;
// stuff_hv = (HV *)sv_2mortal((SV *)newHV());
stuff_hv = newHV();
if( NULL == hv_store( stuff_hv, "SCRIPT_NAME", strlen( "SCRIPT_NAME" ), newSVpv( "", 0 ), 0 ) ) {
croak( "hv_store( 'SCRIPT_NAME' )" );
}
if( NULL == hv_store( stuff_hv, "REQUEST_METHOD", strlen( "REQUEST_METHOD" ), newSVpv( "GET", 3 ), 0 ) ) {
croak( "hv_store( 'REQUEST_METHOD' )" );
}
if( NULL == hv_store( stuff_hv, "REQUEST_URI", strlen( "REQUEST_URI" ), newSVpv( "/abc?def", 8 ), 0 ) ) {
croak( "hv_store( 'REQUEST_URI' )" );
}
if( NULL == hv_store( stuff_hv, "PATH_INFO", strlen( "PATH_INFO" ), newSVpv( "/abc", 4 ), 0 ) ) {
croak( "hv_store( 'PATH_INFO' )" );
}
if( NULL == hv_store( stuff_hv, "QUERY_STRING", strlen( "QUERY_STRING" ), newSVpv( "def", 3 ), 0 ) ) {
croak( "hv_store( 'QUERY_STRING' )" );
}
return newRV_inc( (SV *)stuff_hv );
}
SV * call_stuff( SV *stuff_sv ) {
SV *response_sv;
int count;
// printf( "REQUEST_URI = %s\n", SvPV_nolen( *hv_fetch( (HV *)SvRV( stuff_sv ), "REQUEST_URI", strlen( "REQUEST_URI" ), 0 ) ) );
dSP;
ENTER;
SAVETMPS;
PUSHMARK( SP );
XPUSHs( stuff_sv ); // stuff_sv is not mortal.
PUTBACK;
count = call_sv( app, G_EVAL | G_SCALAR | G_KEEPERR );
SPAGAIN;
if( SvTRUE( ERRSV ) ) {
response_sv = NULL;
fprintf( stderr, "FATAL: %s", SvPV_nolen( ERRSV ) );
/* CLEAR_ERRSV() is only available 5.8.9 or later */
if( SvMAGICAL( ERRSV ) ) {
mg_free( ERRSV );
mg_clear( ERRSV );
}
sv_setpvn_mg( ERRSV, "", 0 );
POPs; // causes "warning: value computed is not used"
}
else if( count > 0 ) {
response_sv = POPs; // is this mortal?
SvREFCNT_inc( response_sv );
} else {
response_sv = NULL;
}
PUTBACK;
FREETMPS;
LEAVE;
return response_sv;
}
You don't free anything! You get a scalar from Perl and you create two yourself, but none of them are getting freed.
Leak 1
You have:
HV *stuff_hv;
stuff_hv = newHV();
return newRV_inc( (SV *)stuff_hv );
Two problems with that:
You're creating an HV with a refcnt of 2.
Change newRV_inc to newRV_noinc.
You never free it (or return it from a XS func as a mortal).
Use SvREFCNT_dec( stuff_sv ) when you're done with it, perhaps after the call to call_stuff.
Leak 2
You have:
body_sv = newSV( 0 );
Again, there's no corresponding freeing of that scalar. You need
SvREFCNT_dec( body_sv );
after the printf.
Leak 3
You have:
response_sv = POPs; // is this mortal?
SvREFCNT_inc( response_sv );
It doesn't really matter if it's mortal or not. You need to claim ownership of it in case it is, so the inc is appropriate. But you must later release it when you're done with it.
SvREFCNT_dec( response_sv );

Resources