Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117748188
bc_emit.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
16 KB
Referenced Files
None
Subscribers
None
bc_emit.c
View Options
/* bc_emit.c -- sieve bytecode - pass 2 of the compiler
* Rob Siemborski
* Jen Smith
* Ken Murchison
*
* Copyright (c) 1994-2018 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any legal
* details, please contact
* Carnegie Mellon University
* Center for Technology Transfer and Enterprise Creation
* 4615 Forbes Avenue
* Suite 302
* Pittsburgh, PA 15213
* (412) 268-7393, fax: (412) 268-7395
* innovation@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include
<config.h>
#endif
#include
"sieve_interface.h"
#include
"bytecode.h"
#include
<syslog.h>
#include
<sys/types.h>
#include
<unistd.h>
#include
<assert.h>
#if DUMPCODE
void
dump
(
bytecode_info_t
*
d
,
int
level
);
#endif
static
inline
int
write_int
(
int
fd
,
int
x
)
{
int
y
=
htonl
(
x
);
return
(
write
(
fd
,
&
y
,
sizeof
(
int
)));
}
/* Pad null bytes onto the end of the string we just wrote */
/* returns -1 on failure or number of bytes written on success */
static
int
align_string
(
int
fd
,
int
string_len
)
{
/* Keep in mind that we always want to pad a string with *at least*
* one zero, that's why sometimes we have to pad with 4 */
int
needed
=
sizeof
(
int
)
-
(
string_len
%
sizeof
(
int
));
if
(
needed
>=
0
&&
needed
<=
4
)
{
if
(
write
(
fd
,
"
\0\0\0\0
"
,
needed
)
==
-1
)
return
-1
;
}
return
needed
;
}
/* all functions keep codep up to date as they use it.
the amount that has been written to the file is maintained by the
filelen variable in bc_action_emit
the other bc_xxx_emit functions keep track of how much they (and any functions
they call) have written and return this value
*/
/* Write out a string to a given file descriptor.
* return # of bytes written on success and -1 on error
* <string:(size)(aligned string)>
*/
static
int
bc_string_emit
(
int
fd
,
int
*
codep
,
bytecode_info_t
*
bc
)
{
int
len
=
bc
->
data
[
*
codep
].
u
.
str
?
(
int
)
strlen
(
bc
->
data
[
*
codep
].
u
.
str
)
:
-1
;
int
wrote
=
0
;
/* Write string length */
if
(
write_int
(
fd
,
len
)
==
-1
)
return
-1
;
wrote
+=
sizeof
(
int
);
if
(
len
==
-1
)
{
/* This is a nil string */
/* Skip the null pointer and make up for it
* by adjusting the offset */
(
*
codep
)
++
;
}
else
{
/* Write string */
if
(
write
(
fd
,
bc
->
data
[(
*
codep
)
++
].
u
.
str
,
len
)
==
-1
)
return
-1
;
int
ret
=
align_string
(
fd
,
len
);
if
(
ret
<
0
)
return
-1
;
wrote
+=
len
+
ret
;
}
return
wrote
;
}
/* Write out a stringlist to a given file descriptor.
* return # of bytes written on success and -1 on error */
/* stringlist: <# listitems>
<pos of listend (bytes)>
<string:(size)(aligned string)>
*/
static
int
bc_stringlist_emit
(
int
fd
,
int
*
codep
,
bytecode_info_t
*
bc
)
{
int
len
=
bc
->
data
[(
*
codep
)
++
].
u
.
listlen
;
int
i
;
int
ret
;
int
wrote
=
2
*
sizeof
(
int
);
int
begin
,
end
;
/* Write out number of items in the list */
if
(
write_int
(
fd
,
len
)
==
-1
)
return
-1
;
/* skip one spot end of list position*/
begin
=
lseek
(
fd
,
0
,
SEEK_CUR
);
lseek
(
fd
,
sizeof
(
int
),
SEEK_CUR
);
/* Loop through all the items of the list, writing out length and string
* in sequence */
for
(
i
=
0
;
i
<
len
;
i
++
)
{
ret
=
bc_string_emit
(
fd
,
codep
,
bc
);
if
(
ret
==
-1
)
return
-1
;
wrote
+=
ret
;
}
end
=
lseek
(
fd
,
0
,
SEEK_CUR
);
if
(
end
<
0
)
return
-1
;
/* go back and write end of list position */
lseek
(
fd
,
begin
,
SEEK_SET
);
if
(
write_int
(
fd
,
end
)
==
-1
)
return
-1
;
/* return to the end */
lseek
(
fd
,
end
,
SEEK_SET
);
return
wrote
;
}
/* Write out a valuelist to a given file descriptor.
* return # of bytes written on success and -1 on error */
/* valuelist: <# listitems>
<pos of listend (bytes)>
<int value>
*/
static
int
bc_vallist_emit
(
int
fd
,
int
*
codep
,
bytecode_info_t
*
bc
)
{
int
len
=
bc
->
data
[(
*
codep
)
++
].
u
.
listlen
;
int
i
;
int
ret
;
int
wrote
=
2
*
sizeof
(
int
);
int
begin
,
end
;
/* Write out number of items in the list */
if
(
write_int
(
fd
,
len
)
==
-1
)
return
-1
;
/* skip one spot end of list position*/
begin
=
lseek
(
fd
,
0
,
SEEK_CUR
);
lseek
(
fd
,
sizeof
(
int
),
SEEK_CUR
);
/* Loop through all the items of the list, writing out length and string
* in sequence */
for
(
i
=
0
;
i
<
len
;
i
++
)
{
ret
=
write_int
(
fd
,
bc
->
data
[(
*
codep
)
++
].
u
.
value
);
if
(
ret
==
-1
)
return
-1
;
wrote
+=
ret
;
}
end
=
lseek
(
fd
,
0
,
SEEK_CUR
);
if
(
end
<
0
)
return
-1
;
/* go back and write end of list position */
lseek
(
fd
,
begin
,
SEEK_SET
);
if
(
write_int
(
fd
,
end
)
==
-1
)
return
-1
;
/* return to the end */
lseek
(
fd
,
end
,
SEEK_SET
);
return
wrote
;
}
static
int
bc_params_emit
(
int
fd
,
int
*
codep
,
int
stopcodep
,
bytecode_info_t
*
bc
)
{
int
ret
;
int
wrote
=
0
;
while
(
*
codep
<
stopcodep
)
{
switch
(
bc
->
data
[
*
codep
].
type
)
{
case
BT_OPCODE
:
case
BT_JUMP
:
/* Next command (end of parameters) */
return
wrote
;
case
BT_VALUE
:
ret
=
write_int
(
fd
,
bc
->
data
[(
*
codep
)
++
].
u
.
value
);
break
;
case
BT_STR
:
ret
=
bc_string_emit
(
fd
,
codep
,
bc
);
break
;
case
BT_STRLISTLEN
:
ret
=
bc_stringlist_emit
(
fd
,
codep
,
bc
);
break
;
case
BT_VALLISTLEN
:
ret
=
bc_vallist_emit
(
fd
,
codep
,
bc
);
break
;
default
:
/* Should never get here */
ret
=
-1
;
break
;
}
if
(
ret
<
0
)
return
-1
;
wrote
+=
ret
;
}
return
wrote
;
}
static
int
bc_test_emit
(
int
fd
,
int
*
codep
,
int
stopcodep
,
bytecode_info_t
*
bc
);
/* Write out a testlist to a given file descriptor.
* return # of bytes written on success and -1 on error */
static
int
bc_testlist_emit
(
int
fd
,
int
*
codep
,
bytecode_info_t
*
bc
)
{
assert
(
bc
->
data
[
*
codep
].
type
==
BT_STRLISTLEN
);
int
len
=
bc
->
data
[(
*
codep
)
++
].
u
.
listlen
;
int
i
;
int
ret
;
int
begin
,
end
;
int
wrote
=
2
*
sizeof
(
int
);
/* Write out number of items in the list */
if
(
write_int
(
fd
,
len
)
==
-1
)
return
-1
;
/* skip one spot for end of list position*/
begin
=
lseek
(
fd
,
0
,
SEEK_CUR
);
lseek
(
fd
,
sizeof
(
int
),
SEEK_CUR
);
/* Loop through all the items of the list, writing out each
* test as we reach it in sequence. */
for
(
i
=
0
;
i
<
len
;
i
++
)
{
assert
(
bc
->
data
[
*
codep
].
type
==
BT_JUMP
);
int
nextcodep
=
bc
->
data
[(
*
codep
)
++
].
u
.
jump
;
ret
=
bc_test_emit
(
fd
,
codep
,
nextcodep
,
bc
);
if
(
ret
<
0
)
return
-1
;
wrote
+=
ret
;
*
codep
=
nextcodep
;
}
end
=
lseek
(
fd
,
0
,
SEEK_CUR
);
if
(
end
<
0
)
return
-1
;
/* go back and write the end of list position */
lseek
(
fd
,
begin
,
SEEK_SET
);
if
(
write_int
(
fd
,
end
)
==
-1
)
return
-1
;
/*return to the end */
lseek
(
fd
,
end
,
SEEK_SET
);
return
wrote
;
}
/* emit the bytecode for a test. returns -1 on failure or size of
* emitted bytecode on success */
static
int
bc_test_emit
(
int
fd
,
int
*
codep
,
int
stopcodep
,
bytecode_info_t
*
bc
)
{
int
opcode
;
int
wrote
=
0
;
/* Relative offset to account for interleaved strings */
int
ret
;
/* Temporary Return Value Variable */
assert
(
bc
->
data
[
*
codep
].
type
==
BT_OPCODE
);
/* Output this opcode */
opcode
=
bc
->
data
[(
*
codep
)
++
].
u
.
op
;
ret
=
write_int
(
fd
,
opcode
);
if
(
ret
<
0
)
return
-1
;
wrote
+=
ret
;
switch
(
opcode
)
{
case
BC_NOT
:
/* Single parameter: another test */
ret
=
bc_test_emit
(
fd
,
codep
,
stopcodep
,
bc
);
break
;
case
BC_ALLOF
:
case
BC_ANYOF
:
/* Just drop a testlist */
ret
=
bc_testlist_emit
(
fd
,
codep
,
bc
);
break
;
case
BC_TRUE
:
case
BC_FALSE
:
case
BC_SIZE
:
case
BC_EXISTS
:
case
BC_IHAVE
:
case
BC_VALIDEXTLIST
:
case
BC_VALIDNOTIFYMETHOD
:
case
BC_NOTIFYMETHODCAPABILITY
:
case
BC_HEADER
:
case
BC_HASFLAG
:
case
BC_STRING
:
case
BC_ADDRESS
:
case
BC_ENVELOPE
:
case
BC_BODY
:
case
BC_MAILBOXEXISTS
:
case
BC_MAILBOXIDEXISTS
:
case
BC_METADATA
:
case
BC_METADATAEXISTS
:
case
BC_SPECIALUSEEXISTS
:
case
BC_SERVERMETADATA
:
case
BC_ENVIRONMENT
:
case
BC_SERVERMETADATAEXISTS
:
case
BC_DATE
:
case
BC_CURRENTDATE
:
case
BC_DUPLICATE
:
case
BC_JMAPQUERY
:
ret
=
bc_params_emit
(
fd
,
codep
,
stopcodep
,
bc
);
break
;
default
:
/* Unknown testcode? */
ret
=
-1
;
break
;
}
if
(
ret
<
0
)
return
-1
;
wrote
+=
ret
;
return
wrote
;
}
/* emit the bytecode to a file descriptor given a flattened parse tree
* returns -1 on failure, size of emitted bytecode on success.
*
* this takes care of everything except the comparisons */
static
int
bc_action_emit
(
int
fd
,
int
codep
,
int
stopcodep
,
bytecode_info_t
*
bc
,
int
filelen
)
{
int
ret
;
/* Temporary Return Value Variable */
int
start_filelen
=
filelen
;
/*debugging variable to check filelen*/
/*int location;*/
syslog
(
LOG_DEBUG
,
"entered bc_action_emit with filelen: %d"
,
filelen
);
/* All non-string data MUST be sizeof(int)
byte aligned so the end of each string may require a pad */
/*
* Note that for purposes of jumps you must multiply codep by sizeof(int)
*/
while
(
codep
<
stopcodep
)
{
assert
(
bc
->
data
[
codep
].
type
==
BT_OPCODE
);
/* Output this opcode */
if
(
write_int
(
fd
,
bc
->
data
[
codep
].
u
.
op
)
==
-1
)
return
-1
;
filelen
+=
sizeof
(
int
);
switch
(
bc
->
data
[
codep
++
].
u
.
op
)
{
case
B_IF
:
{
/* IF
* pos of testend (bytes)
* test
* jump (false condition)
* then
* (if there is an else) jump(finish)
* (if there is an else) else
*/
int
testEndLoc
=
-1
;
int
testdist
,
thendist
,
elsedist
;
int
c
;
int
jumpFalseLoc
=
-1
;
/* this is the location that is being reserved
for the first jump command
we jump to the false condition of the test */
int
jumpEndLoc
=
-1
;
/* this is the location that is being reserved
for the optional jump command
it jumps over the else statement to the end */
int
jumpto
=
-1
;
int
jumpop
=
B_JUMP
;
/* leave space to store the location of end of the test */
ret
=
lseek
(
fd
,
sizeof
(
int
),
SEEK_CUR
);
if
(
ret
==
-1
)
return
ret
;
testEndLoc
=
filelen
;
filelen
+=
sizeof
(
int
);
/* spew the test */
c
=
codep
+
3
;
testdist
=
bc_test_emit
(
fd
,
&
c
,
bc
->
data
[
codep
].
u
.
jump
,
bc
);
if
(
testdist
==
-1
)
return
-1
;
filelen
+=
testdist
;
/* store the location for the end of the test
* this is important for short circuiting of allof/anyof */
jumpto
=
filelen
/
4
;
if
(
lseek
(
fd
,
testEndLoc
,
SEEK_SET
)
==
-1
)
return
-1
;
if
(
write_int
(
fd
,
jumpto
)
==
-1
)
return
-1
;
if
(
lseek
(
fd
,
filelen
,
SEEK_SET
)
==
-1
)
return
-1
;
/* leave space for jump */
if
(
write_int
(
fd
,
jumpop
)
==
-1
)
return
-1
;
ret
=
lseek
(
fd
,
sizeof
(
int
),
SEEK_CUR
);
if
(
ret
==
-1
)
return
ret
;
jumpFalseLoc
=
filelen
+
sizeof
(
int
);
filelen
+=
2
*
sizeof
(
int
);
/* jumpop + jump */
/* spew the then code */
thendist
=
bc_action_emit
(
fd
,
bc
->
data
[
codep
].
u
.
jump
,
bc
->
data
[
codep
+
1
].
u
.
jump
,
bc
,
filelen
);
filelen
+=
thendist
;
/* there is an else case */
if
(
bc
->
data
[
codep
+
2
].
u
.
jump
!=
-1
)
{
/* leave space for jump */
if
(
write_int
(
fd
,
jumpop
)
==
-1
)
return
-1
;
ret
=
lseek
(
fd
,
sizeof
(
int
),
SEEK_CUR
);
if
(
ret
==
-1
)
return
ret
;
jumpEndLoc
=
filelen
+
sizeof
(
int
);
filelen
+=
2
*
sizeof
(
int
);
/* jumpop + jump */
}
/* put previous jump to the end of the then code,
* or the end of the jump if there is an else case */
jumpto
=
filelen
/
4
;
if
(
lseek
(
fd
,
jumpFalseLoc
,
SEEK_SET
)
==
-1
)
return
-1
;
if
(
write_int
(
fd
,
jumpto
)
==
-1
)
return
-1
;
if
(
lseek
(
fd
,
filelen
,
SEEK_SET
)
==
-1
)
return
-1
;
/* there is an else case */
if
(
bc
->
data
[
codep
+
2
].
u
.
jump
!=
-1
)
{
/* spew the else code */
elsedist
=
bc_action_emit
(
fd
,
bc
->
data
[
codep
+
1
].
u
.
jump
,
bc
->
data
[
codep
+
2
].
u
.
jump
,
bc
,
filelen
);
filelen
+=
elsedist
;
/* put jump to the end of the else code */
jumpto
=
filelen
/
4
;
if
(
lseek
(
fd
,
jumpEndLoc
,
SEEK_SET
)
==
-1
)
return
-1
;
if
(
write_int
(
fd
,
jumpto
)
==
-1
)
return
-1
;
if
(
lseek
(
fd
,
filelen
,
SEEK_SET
)
==
-1
)
return
-1
;
codep
=
bc
->
data
[
codep
+
2
].
u
.
jump
;
}
else
{
codep
=
bc
->
data
[
codep
+
1
].
u
.
jump
;
}
break
;
}
case
B_KEEP
:
case
B_FILEINTO
:
case
B_REDIRECT
:
case
B_REJECT
:
case
B_EREJECT
:
case
B_ERROR
:
case
B_SETFLAG
:
case
B_ADDFLAG
:
case
B_REMOVEFLAG
:
case
B_ENOTIFY
:
case
B_NOTIFY
:
case
B_DENOTIFY
:
case
B_VACATION
:
case
B_INCLUDE
:
case
B_SET
:
case
B_ADDHEADER
:
case
B_DELETEHEADER
:
case
B_LOG
:
case
B_NULL
:
case
B_STOP
:
case
B_DISCARD
:
case
B_MARK
:
case
B_UNMARK
:
case
B_RETURN
:
case
B_SNOOZE
:
/* Spew the action parameters */
ret
=
bc_params_emit
(
fd
,
&
codep
,
stopcodep
,
bc
);
if
(
ret
<
0
)
return
-1
;
filelen
+=
ret
;
break
;
default
:
/* Unknown opcode? */
return
-1
;
}
}
return
filelen
-
start_filelen
;
}
/* spew the bytecode to disk */
EXPORTED
int
sieve_emit_bytecode
(
int
fd
,
bytecode_info_t
*
bc
)
{
int
codep
=
0
;
/* First output version number (4 bytes) */
int
data
=
BYTECODE_VERSION
;
/*this is a string, so it is happy*/
if
(
write
(
fd
,
BYTECODE_MAGIC
,
BYTECODE_MAGIC_LEN
)
==
-1
)
return
-1
;
if
(
write_int
(
fd
,
data
)
==
-1
)
return
-1
;
/* write extensions bitfield */
if
(
write_int
(
fd
,
bc
->
data
[
codep
++
].
u
.
value
)
==
-1
)
return
-1
;
#if DUMPCODE
dump
(
bc
,
0
);
#endif
/* the 2*sizeof(int) is to account for the version number and requires at
* the beginning
*/
return
bc_action_emit
(
fd
,
codep
,
bc
->
scriptend
,
bc
,
2
*
sizeof
(
int
)
+
BYTECODE_MAGIC_LEN
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, Apr 4, 12:50 AM (3 w, 3 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
b3/61/c00b441fe1463d46e5f1aa3ece4d
Default Alt Text
bc_emit.c (16 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline