Switched to a new parameter parsing API, which simplifies the code.

Made error reporting use php_error_docref().
Fixed a memory leak in shmop_open() when an invalid flag is specified.
Added tests for shmop() extension.
This commit is contained in:
Ilia Alshanetsky 2002-11-20 15:56:56 +00:00
parent e532b24d82
commit 7908cffab4
3 changed files with 154 additions and 75 deletions

View File

@ -12,8 +12,8 @@
| obtain it through the world-wide-web, please send a note to | | obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. | | license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
| Authors: Slava Poliakov <slavapl@mailandnews.com> | | Authors: Slava Poliakov <hackie@prohost.org> |
| Ilia Alshanetsky <iliaa@home.com> | | Ilia Alshanetsky <ilia@prohost.org> |
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
*/ */
#ifndef PHP_SHMOP_H #ifndef PHP_SHMOP_H

View File

@ -117,47 +117,44 @@ PHP_MINFO_FUNCTION(shmop)
} }
/* }}} */ /* }}} */
/* {{{ proto int shmop_open (int key, int flags, int mode, int size) /* {{{ proto int shmop_open (int key, string flags, int mode, int size)
gets and attaches a shared memory segment */ gets and attaches a shared memory segment */
PHP_FUNCTION(shmop_open) PHP_FUNCTION(shmop_open)
{ {
zval **key, **flags, **mode, **size; long key, mode, size;
struct php_shmop *shmop; struct php_shmop *shmop;
struct shmid_ds shm; struct shmid_ds shm;
int rsid; int rsid;
char *flags;
int flags_len;
if (ZEND_NUM_ARGS() != 4 || zend_get_parameters_ex(4, &key, &flags, &mode, &size) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
WRONG_PARAM_COUNT; WRONG_PARAM_COUNT;
} }
convert_to_long_ex(key); if (flags_len != 1) {
convert_to_string_ex(flags); php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a valid flag", flags);
convert_to_long_ex(mode); RETURN_FALSE;
convert_to_long_ex(size); }
shmop = emalloc(sizeof(struct php_shmop)); shmop = emalloc(sizeof(struct php_shmop));
memset(shmop, 0, sizeof(struct php_shmop)); memset(shmop, 0, sizeof(struct php_shmop));
shmop->key = (*key)->value.lval; shmop->key = key;
shmop->shmflg |= (*mode)->value.lval; shmop->shmflg |= mode;
if( (*flags)->value.str.len != 1 ) { switch (flags[0])
php_error(E_WARNING, "shmop_open: invalid flag");
RETURN_FALSE;
}
switch( (*flags)->value.str.val[0] )
{ {
case 'a': case 'a':
shmop->shmatflg |= SHM_RDONLY; shmop->shmatflg |= SHM_RDONLY;
break; break;
case 'c': case 'c':
shmop->shmflg |= IPC_CREAT; shmop->shmflg |= IPC_CREAT;
shmop->size = (*size)->value.lval; shmop->size = size;
break; break;
case 'n': case 'n':
shmop->shmflg |= (IPC_CREAT|IPC_EXCL); shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
shmop->size = (*size)->value.lval; shmop->size = size;
break; break;
case 'w': case 'w':
/* noop /* noop
@ -166,28 +163,28 @@ PHP_FUNCTION(shmop_open)
*/ */
break; break;
default: default:
php_error(E_WARNING, "shmop_open: invalid access mode"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid access mode");
efree(shmop); efree(shmop);
RETURN_FALSE; RETURN_FALSE;
} }
shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg); shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
if (shmop->shmid == -1) { if (shmop->shmid == -1) {
php_error(E_WARNING, "shmop_open: unable to attach or create shm segment"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach or create shared memory segment");
efree(shmop); efree(shmop);
RETURN_FALSE; RETURN_FALSE;
} }
if (shmctl(shmop->shmid, IPC_STAT, &shm)) { if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
efree(shmop); efree(shmop);
php_error(E_WARNING, "shmop_open: unable to get shm segment information"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get shared memory segment information");
RETURN_FALSE; RETURN_FALSE;
} }
shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg); shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
if (shmop->addr == (char*) -1) { if (shmop->addr == (char*) -1) {
efree(shmop); efree(shmop);
php_error(E_WARNING, "shmop_open: unable to attach to shm segment"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach to shared memory segment");
RETURN_FALSE; RETURN_FALSE;
} }
@ -202,45 +199,41 @@ PHP_FUNCTION(shmop_open)
reads from a shm segment */ reads from a shm segment */
PHP_FUNCTION(shmop_read) PHP_FUNCTION(shmop_read)
{ {
zval **shmid, **start, **count; long shmid, start, count;
struct php_shmop *shmop; struct php_shmop *shmop;
int type; int type;
char *startaddr; char *startaddr;
int bytes; int bytes;
char *return_string; char *return_string;
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &shmid, &start, &count) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &shmid, &start, &count) == FAILURE) {
WRONG_PARAM_COUNT; WRONG_PARAM_COUNT;
} }
convert_to_long_ex(shmid); shmop = zend_list_find(shmid, &type);
convert_to_long_ex(start);
convert_to_long_ex(count);
shmop = zend_list_find((*shmid)->value.lval, &type);
if (!shmop) { if (!shmop) {
php_error(E_WARNING, "shmop_read: can't find this segment"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid);
RETURN_FALSE;
}
if (start < 0 || start > shmop->size) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
RETURN_FALSE; RETURN_FALSE;
} }
if ((*start)->value.lval < 0 || (*start)->value.lval > shmop->size) { if (start + count > shmop->size) {
php_error(E_WARNING, "shmop_read: start is out of range"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
RETURN_FALSE; RETURN_FALSE;
} }
if (((*start)->value.lval+(*count)->value.lval) > shmop->size) { if (count < 0 ){
php_error(E_WARNING, "shmop_read: count is out of range"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
RETURN_FALSE; RETURN_FALSE;
} }
if ((*count)->value.lval < 0 ){ startaddr = shmop->addr + start;
php_error(E_WARNING, "shmop_read: count is out of range"); bytes = count ? count : shmop->size - start;
RETURN_FALSE;
}
startaddr = shmop->addr + (*start)->value.lval;
bytes = (*count)->value.lval ? (*count)->value.lval : shmop->size-(*start)->value.lval;
return_string = emalloc(bytes+1); return_string = emalloc(bytes+1);
memcpy(return_string, startaddr, bytes); memcpy(return_string, startaddr, bytes);
@ -254,21 +247,22 @@ PHP_FUNCTION(shmop_read)
closes a shared memory segment */ closes a shared memory segment */
PHP_FUNCTION(shmop_close) PHP_FUNCTION(shmop_close)
{ {
zval **shmid; long shmid;
struct php_shmop *shmop; struct php_shmop *shmop;
int type; int type;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &shmid) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
WRONG_PARAM_COUNT; WRONG_PARAM_COUNT;
} }
shmop = zend_list_find((*shmid)->value.lval, &type); shmop = zend_list_find(shmid, &type);
if (!shmop) { if (!shmop) {
php_error(E_WARNING, "shmop_close: no such shmid"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid);
RETURN_FALSE; RETURN_FALSE;
} }
zend_list_delete((*shmid)->value.lval);
zend_list_delete(shmid);
} }
/* }}} */ /* }}} */
@ -276,20 +270,18 @@ PHP_FUNCTION(shmop_close)
returns the shm size */ returns the shm size */
PHP_FUNCTION(shmop_size) PHP_FUNCTION(shmop_size)
{ {
zval **shmid; long shmid;
struct php_shmop *shmop; struct php_shmop *shmop;
int type; int type;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &shmid) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
WRONG_PARAM_COUNT; WRONG_PARAM_COUNT;
} }
convert_to_long_ex(shmid); shmop = zend_list_find(shmid, &type);
shmop = zend_list_find((*shmid)->value.lval, &type);
if (!shmop) { if (!shmop) {
php_error(E_WARNING, "shmop_size: no such segment"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid);
RETURN_FALSE; RETURN_FALSE;
} }
@ -301,38 +293,36 @@ PHP_FUNCTION(shmop_size)
writes to a shared memory segment */ writes to a shared memory segment */
PHP_FUNCTION(shmop_write) PHP_FUNCTION(shmop_write)
{ {
zval **shmid, **data, **offset;
struct php_shmop *shmop; struct php_shmop *shmop;
int type; int type;
int writesize; int writesize;
long shmid, offset;
char *data;
int data_len;
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &shmid, &data, &offset) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &shmid, &data, &data_len, &offset) == FAILURE) {
WRONG_PARAM_COUNT; WRONG_PARAM_COUNT;
} }
convert_to_long_ex(shmid); shmop = zend_list_find(shmid, &type);
convert_to_string_ex(data);
convert_to_long_ex(offset);
shmop = zend_list_find((*shmid)->value.lval, &type);
if (!shmop) { if (!shmop) {
php_error(E_WARNING, "shmop_write: error no such segment"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid);
RETURN_FALSE; RETURN_FALSE;
} }
if( (shmop->shmatflg&SHM_RDONLY) == SHM_RDONLY ) { if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
php_error(E_WARNING, "shmop_write: trying to write to a read only segment"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to write to a read only segment");
RETURN_FALSE; RETURN_FALSE;
} }
if ( (*offset)->value.lval > shmop->size ) { if (offset > shmop->size) {
php_error(E_WARNING, "shmop_write: offset out of range"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset out of range");
RETURN_FALSE; RETURN_FALSE;
} }
writesize = ((*data)->value.str.len<shmop->size-(*offset)->value.lval) ? (*data)->value.str.len : shmop->size-(*offset)->value.lval; writesize = (data_len < shmop->size - offset) ? data_len : shmop->size - offset;
memcpy(shmop->addr+(*offset)->value.lval, (*data)->value.str.val, writesize); memcpy(shmop->addr + offset, data, writesize);
RETURN_LONG(writesize); RETURN_LONG(writesize);
} }
@ -342,25 +332,23 @@ PHP_FUNCTION(shmop_write)
mark segment for deletion */ mark segment for deletion */
PHP_FUNCTION(shmop_delete) PHP_FUNCTION(shmop_delete)
{ {
zval **shmid; long shmid;
struct php_shmop *shmop; struct php_shmop *shmop;
int type; int type;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &shmid) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
WRONG_PARAM_COUNT; WRONG_PARAM_COUNT;
} }
convert_to_long_ex(shmid); shmop = zend_list_find(shmid, &type);
shmop = zend_list_find((*shmid)->value.lval, &type);
if (!shmop) { if (!shmop) {
php_error(E_WARNING, "shmop_delete: error no such segment"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid);
RETURN_FALSE; RETURN_FALSE;
} }
if (shmctl(shmop->shmid, IPC_RMID, NULL)) { if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
php_error(E_WARNING, "shmop_delete: can't mark segment for deletion (are you the owner?)"); php_error_docref(NULL TSRMLS_CC, E_WARNING, "can't mark segment for deletion (are you the owner?)");
RETURN_FALSE; RETURN_FALSE;
} }

91
ext/shmop/tests/001.phpt Normal file
View File

@ -0,0 +1,91 @@
--TEST--
shmop extension test
--SKIPIF--
<?php
if (!extension_loaded("shmop")) {
die("skip shmop() extension not avaliable");
}
?>
--FILE--
<?php
$hex_shm_id = 0xff3;
$write_d1 = "test #1 of the shmop() extension";
$write_d2 = "test #2 append data to shared memory segment";
echo "shm open for create: ";
$shm_id = shmop_open($hex_shm_id, "n", 0644, 1024);
if (!$shm_id) {
die("failed\n");
} else {
echo "ok\n";
}
echo "shm size is: " . ($shm_size = shmop_size($shm_id)) . "\n";
echo "shm write test #1: ";
$written = shmop_write($shm_id, $write_d1, 0);
if ($written != strlen($write_d1)) {
echo "failed\n";
} else {
echo "ok\n";
}
echo "data in memory is: " . shmop_read($shm_id, 0, $written) . "\n";
shmop_close($shm_id);
echo "shm open for read only: ";
$shm_id = shmop_open($hex_shm_id, "a", 0644, 1024);
if (!$shm_id) {
echo "failed\n";
} else {
echo "ok\n";
}
echo "data in memory is: " . shmop_read($shm_id, 0, $written) . "\n";
/* try to append data to the shared memory segment, this should fail */
@shmop_write($shm_id, $write_d1, $written);
echo $php_errormsg . "\n";
shmop_close($shm_id);
echo "shm open for read only: ";
$shm_id = shmop_open($hex_shm_id, "w", 0644, 1024);
if (!$shm_id) {
echo "failed\n";
} else {
echo "ok\n";
}
echo "shm write test #1: ";
$written = shmop_write($shm_id, $write_d2, $written);
if ($written != strlen($write_d2)) {
die("failed\n");
} else {
echo "ok\n";
}
echo "data in memory is: " . shmop_read($shm_id, 0, strlen($write_d1 . $write_d2)) . "\n";
echo "deletion of shm segment: ";
if (!shmop_delete($shm_id)) {
echo "failed\n";
} else {
echo "ok\n";
}
shmop_close($shm_id);
?>
--EXPECT--
shm open for create: ok
shm size is: 1024
shm write test #1: ok
data in memory is: test #1 of the shmop() extension
shm open for read only: ok
data in memory is: test #1 of the shmop() extension
trying to write to a read only segment
shm open for read only: ok
shm write test #1: ok
data in memory is: test #1 of the shmop() extensiontest #2 append data to shared memory segment
deletion of shm segment: ok