mirror of
https://github.com/php/php-src.git
synced 2024-09-22 02:17:32 +00:00
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:
parent
e532b24d82
commit
7908cffab4
@ -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
|
||||||
|
@ -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;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*start)->value.lval < 0 || (*start)->value.lval > shmop->size) {
|
if (start < 0 || start > shmop->size) {
|
||||||
php_error(E_WARNING, "shmop_read: start is out of range");
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((*start)->value.lval+(*count)->value.lval) > shmop->size) {
|
if (start + count > shmop->size) {
|
||||||
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 ){
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
startaddr = shmop->addr + (*start)->value.lval;
|
startaddr = shmop->addr + start;
|
||||||
bytes = (*count)->value.lval ? (*count)->value.lval : shmop->size-(*start)->value.lval;
|
bytes = count ? count : shmop->size - start;
|
||||||
|
|
||||||
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
91
ext/shmop/tests/001.phpt
Normal 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
|
Loading…
Reference in New Issue
Block a user