fixed a very serious flaw where Vectors being passed as pointers would corrupt the vector object values. this caused TeleportEntity() to have very weird effects
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40993
This commit is contained in:
parent
c2d1cc5ab5
commit
e29e6c216e
@ -60,17 +60,22 @@ ValveCall *CreateValveCall(void *addr,
|
|||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
vc->stackSize = 0;
|
vc->stackSize = 0;
|
||||||
|
|
||||||
/* Get return information - encode only*/
|
/* Get return information - encode only */
|
||||||
PassInfo retBuf;
|
PassInfo retBuf;
|
||||||
size_t retBufSize = 0;
|
size_t retBufSize = 0;
|
||||||
|
bool retbuf_needs_extra;
|
||||||
if (retInfo)
|
if (retInfo)
|
||||||
{
|
{
|
||||||
if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf)) == 0)
|
if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
|
||||||
{
|
{
|
||||||
delete vc;
|
delete vc;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
retBufSize = size;
|
retBufSize = retBuf.size;
|
||||||
|
if (retbuf_needs_extra)
|
||||||
|
{
|
||||||
|
retBufSize += size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get thisinfo if needed */
|
/* Get thisinfo if needed */
|
||||||
@ -98,14 +103,29 @@ ValveCall *CreateValveCall(void *addr,
|
|||||||
|
|
||||||
/* Get parameter info */
|
/* Get parameter info */
|
||||||
PassInfo paramBuf[32];
|
PassInfo paramBuf[32];
|
||||||
|
size_t sizes[32];
|
||||||
|
size_t normSize = 0;
|
||||||
|
size_t extraSize = 0;
|
||||||
for (unsigned int i=0; i<numParams; i++)
|
for (unsigned int i=0; i<numParams; i++)
|
||||||
{
|
{
|
||||||
if ((size = ValveParamToBinParam(params[i].vtype, params[i].type, params[i].flags, ¶mBuf[i])) == 0)
|
bool needs_extra;
|
||||||
|
if ((size = ValveParamToBinParam(params[i].vtype,
|
||||||
|
params[i].type,
|
||||||
|
params[i].flags,
|
||||||
|
¶mBuf[i],
|
||||||
|
needs_extra)) == 0)
|
||||||
{
|
{
|
||||||
delete vc;
|
delete vc;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
vc->stackSize += size;
|
if (needs_extra)
|
||||||
|
{
|
||||||
|
sizes[i] = size;
|
||||||
|
} else {
|
||||||
|
sizes[i] = 0;
|
||||||
|
}
|
||||||
|
normSize += paramBuf[i].size;
|
||||||
|
extraSize += sizes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we can try creating the call */
|
/* Now we can try creating the call */
|
||||||
@ -135,6 +155,7 @@ ValveCall *CreateValveCall(void *addr,
|
|||||||
vc->retinfo = &(vc->vparams[numParams]);
|
vc->retinfo = &(vc->vparams[numParams]);
|
||||||
*vc->retinfo = *retInfo;
|
*vc->retinfo = *retInfo;
|
||||||
vc->retinfo->offset = 0;
|
vc->retinfo->offset = 0;
|
||||||
|
vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0;
|
||||||
/* Allocate stack space */
|
/* Allocate stack space */
|
||||||
vc->retbuf = new unsigned char[retBufSize];
|
vc->retbuf = new unsigned char[retBufSize];
|
||||||
} else {
|
} else {
|
||||||
@ -148,18 +169,25 @@ ValveCall *CreateValveCall(void *addr,
|
|||||||
vc->thisinfo = &(vc->vparams[numParams + 1]);
|
vc->thisinfo = &(vc->vparams[numParams + 1]);
|
||||||
*vc->thisinfo = *thisinfo;
|
*vc->thisinfo = *thisinfo;
|
||||||
vc->thisinfo->offset = 0;
|
vc->thisinfo->offset = 0;
|
||||||
|
vc->thisinfo->obj_offset = 0;
|
||||||
} else {
|
} else {
|
||||||
vc->thisinfo = NULL;
|
vc->thisinfo = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now, save info about each parameter. */
|
/* Now, save info about each parameter. */
|
||||||
|
size_t last_extra_offset = 0;
|
||||||
for (unsigned int i=0; i<numParams; i++)
|
for (unsigned int i=0; i<numParams; i++)
|
||||||
{
|
{
|
||||||
/* Copy */
|
/* Copy */
|
||||||
vc->vparams[i] = params[i];
|
vc->vparams[i] = params[i];
|
||||||
vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
|
vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
|
||||||
|
vc->vparams[i].obj_offset = last_extra_offset;
|
||||||
|
last_extra_offset += sizes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vc->stackSize = normSize + extraSize;
|
||||||
|
vc->stackEnd = normSize;
|
||||||
|
|
||||||
return vc;
|
return vc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,29 +207,49 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx,
|
|||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
vc->stackSize = 0;
|
vc->stackSize = 0;
|
||||||
|
|
||||||
/* Get return information - encode only*/
|
/* Get return information - encode only */
|
||||||
PassInfo retBuf;
|
PassInfo retBuf;
|
||||||
size_t retBufSize = 0;
|
size_t retBufSize = 0;
|
||||||
|
bool retbuf_needs_extra;
|
||||||
if (retInfo)
|
if (retInfo)
|
||||||
{
|
{
|
||||||
if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf)) == 0)
|
if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
|
||||||
{
|
{
|
||||||
delete vc;
|
delete vc;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
retBufSize = size;
|
retBufSize = retBuf.size;
|
||||||
|
if (retbuf_needs_extra)
|
||||||
|
{
|
||||||
|
retBufSize += size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get parameter info */
|
/* Get parameter info */
|
||||||
PassInfo paramBuf[32];
|
PassInfo paramBuf[32];
|
||||||
|
size_t sizes[32];
|
||||||
|
size_t normSize = 0;
|
||||||
|
size_t extraSize = 0;
|
||||||
for (unsigned int i=0; i<numParams; i++)
|
for (unsigned int i=0; i<numParams; i++)
|
||||||
{
|
{
|
||||||
if ((size = ValveParamToBinParam(params[i].vtype, params[i].type, params[i].flags, ¶mBuf[i])) == 0)
|
bool needs_extra;
|
||||||
|
if ((size = ValveParamToBinParam(params[i].vtype,
|
||||||
|
params[i].type,
|
||||||
|
params[i].flags,
|
||||||
|
¶mBuf[i],
|
||||||
|
needs_extra)) == 0)
|
||||||
{
|
{
|
||||||
delete vc;
|
delete vc;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
vc->stackSize += size;
|
if (needs_extra)
|
||||||
|
{
|
||||||
|
sizes[i] = size;
|
||||||
|
} else {
|
||||||
|
sizes[i] = 0;
|
||||||
|
}
|
||||||
|
normSize += paramBuf[i].size;
|
||||||
|
extraSize += sizes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we can try creating the call */
|
/* Now we can try creating the call */
|
||||||
@ -232,6 +280,7 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx,
|
|||||||
vc->retinfo = &(vc->vparams[numParams]);
|
vc->retinfo = &(vc->vparams[numParams]);
|
||||||
*vc->retinfo = *retInfo;
|
*vc->retinfo = *retInfo;
|
||||||
vc->retinfo->offset = 0;
|
vc->retinfo->offset = 0;
|
||||||
|
vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0;
|
||||||
/* Allocate stack space */
|
/* Allocate stack space */
|
||||||
vc->retbuf = new unsigned char[retBufSize];
|
vc->retbuf = new unsigned char[retBufSize];
|
||||||
} else {
|
} else {
|
||||||
@ -253,15 +302,22 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx,
|
|||||||
vc->thisinfo->encflags = 0;
|
vc->thisinfo->encflags = 0;
|
||||||
vc->thisinfo->flags = PASSFLAG_BYVAL;
|
vc->thisinfo->flags = PASSFLAG_BYVAL;
|
||||||
vc->thisinfo->offset = 0;
|
vc->thisinfo->offset = 0;
|
||||||
vc->stackSize += sizeof(void *);
|
vc->thisinfo->obj_offset = 0;
|
||||||
|
normSize += sizeof(void *);
|
||||||
|
|
||||||
/* Now, save info about each parameter. */
|
/* Now, save info about each parameter. */
|
||||||
|
size_t last_extra_offset = 0;
|
||||||
for (unsigned int i=0; i<numParams; i++)
|
for (unsigned int i=0; i<numParams; i++)
|
||||||
{
|
{
|
||||||
/* Copy */
|
/* Copy */
|
||||||
vc->vparams[i] = params[i];
|
vc->vparams[i] = params[i];
|
||||||
vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
|
vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
|
||||||
|
vc->vparams[i].obj_offset = last_extra_offset;
|
||||||
|
last_extra_offset += sizes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vc->stackSize = normSize + extraSize;
|
||||||
|
vc->stackEnd = normSize;
|
||||||
|
|
||||||
return vc;
|
return vc;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ struct ValveCall
|
|||||||
ValvePassInfo *retinfo; /**< Return buffer info */
|
ValvePassInfo *retinfo; /**< Return buffer info */
|
||||||
ValvePassInfo *thisinfo; /**< Thiscall info */
|
ValvePassInfo *thisinfo; /**< Thiscall info */
|
||||||
size_t stackSize; /**< Stack size */
|
size_t stackSize; /**< Stack size */
|
||||||
|
size_t stackEnd; /**< End of the bintools stack */
|
||||||
unsigned char *retbuf; /**< Return buffer */
|
unsigned char *retbuf; /**< Return buffer */
|
||||||
CStack<unsigned char *> stk; /**< Parameter stack */
|
CStack<unsigned char *> stk; /**< Parameter stack */
|
||||||
|
|
||||||
|
@ -233,6 +233,7 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
|||||||
}
|
}
|
||||||
if (DecodeValveParam(pContext,
|
if (DecodeValveParam(pContext,
|
||||||
params[startparam],
|
params[startparam],
|
||||||
|
vc,
|
||||||
vc->thisinfo,
|
vc->thisinfo,
|
||||||
ptr) == Data_Fail)
|
ptr) == Data_Fail)
|
||||||
{
|
{
|
||||||
@ -268,8 +269,9 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
|||||||
}
|
}
|
||||||
if (DecodeValveParam(pContext,
|
if (DecodeValveParam(pContext,
|
||||||
params[p],
|
params[p],
|
||||||
|
vc,
|
||||||
&(vc->vparams[i]),
|
&(vc->vparams[i]),
|
||||||
ptr + vc->vparams[i].offset) == Data_Fail)
|
ptr) == Data_Fail)
|
||||||
{
|
{
|
||||||
vc->stk_put(ptr);
|
vc->stk_put(ptr);
|
||||||
return 0;
|
return 0;
|
||||||
@ -292,8 +294,9 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
|||||||
{
|
{
|
||||||
if (EncodeValveParam(pContext,
|
if (EncodeValveParam(pContext,
|
||||||
startparam + i,
|
startparam + i,
|
||||||
|
vc,
|
||||||
&vc->vparams[i],
|
&vc->vparams[i],
|
||||||
ptr + vc->vparams[i].offset) == Data_Fail)
|
ptr) == Data_Fail)
|
||||||
{
|
{
|
||||||
vc->stk_put(ptr);
|
vc->stk_put(ptr);
|
||||||
return 0;
|
return 0;
|
||||||
@ -326,7 +329,7 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
|||||||
{
|
{
|
||||||
return pContext->ThrowNativeError("Expected argument (2) for Float[3] storage");
|
return pContext->ThrowNativeError("Expected argument (2) for Float[3] storage");
|
||||||
}
|
}
|
||||||
if (EncodeValveParam(pContext, params[retparam], vc->retinfo, vc->retbuf)
|
if (EncodeValveParam(pContext, params[retparam], vc, vc->retinfo, vc->retbuf)
|
||||||
== Data_Fail)
|
== Data_Fail)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
#include "smsdk_ext.h"
|
#include "smsdk_ext.h"
|
||||||
#include "extension.h"
|
#include "extension.h"
|
||||||
#include "vdecoder.h"
|
#include "vdecoder.h"
|
||||||
|
#include "vcallbuilder.h"
|
||||||
|
|
||||||
using namespace SourceMod;
|
using namespace SourceMod;
|
||||||
using namespace SourcePawn;
|
using namespace SourcePawn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For object pointers, the data looks like this instead:
|
* For object pointers, the data looks like this instead:
|
||||||
* 4 bytes: POINTER TO NEXT FOUR BYTES
|
* 4 bytes: POINTER TO LATER
|
||||||
* + bytes: Object internal data
|
* + bytes: Object internal data
|
||||||
*
|
*
|
||||||
* We use the virtual stack as extra fake stack space and create a temp object.
|
* We use the virtual stack as extra fake stack space and create a temp object.
|
||||||
@ -18,8 +19,10 @@ using namespace SourcePawn;
|
|||||||
size_t ValveParamToBinParam(ValveType type,
|
size_t ValveParamToBinParam(ValveType type,
|
||||||
PassType pass,
|
PassType pass,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
PassInfo *info)
|
PassInfo *info,
|
||||||
|
bool &needs_extra)
|
||||||
{
|
{
|
||||||
|
needs_extra = false;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case Valve_Vector:
|
case Valve_Vector:
|
||||||
@ -34,7 +37,8 @@ size_t ValveParamToBinParam(ValveType type,
|
|||||||
info->type = PassType_Basic;
|
info->type = PassType_Basic;
|
||||||
info->flags = flags;
|
info->flags = flags;
|
||||||
info->size = sizeof(Vector *);
|
info->size = sizeof(Vector *);
|
||||||
mySize += sizeof(Vector);
|
mySize = sizeof(Vector);
|
||||||
|
needs_extra = true;
|
||||||
} else if (pass == PassType_Object) {
|
} else if (pass == PassType_Object) {
|
||||||
info->type = PassType_Object;
|
info->type = PassType_Object;
|
||||||
info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
|
info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
|
||||||
@ -56,7 +60,8 @@ size_t ValveParamToBinParam(ValveType type,
|
|||||||
info->type = PassType_Basic;
|
info->type = PassType_Basic;
|
||||||
info->flags = flags;
|
info->flags = flags;
|
||||||
info->size = sizeof(QAngle *);
|
info->size = sizeof(QAngle *);
|
||||||
mySize += sizeof(QAngle);
|
mySize = sizeof(QAngle);
|
||||||
|
needs_extra = true;
|
||||||
} else if (pass == PassType_Object) {
|
} else if (pass == PassType_Object) {
|
||||||
info->type = PassType_Object;
|
info->type = PassType_Object;
|
||||||
info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
|
info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
|
||||||
@ -126,9 +131,11 @@ size_t ValveParamToBinParam(ValveType type,
|
|||||||
|
|
||||||
DataStatus EncodeValveParam(IPluginContext *pContext,
|
DataStatus EncodeValveParam(IPluginContext *pContext,
|
||||||
cell_t param,
|
cell_t param,
|
||||||
|
const ValveCall *pCall,
|
||||||
const ValvePassInfo *data,
|
const ValvePassInfo *data,
|
||||||
const void *buffer)
|
const void *_buffer)
|
||||||
{
|
{
|
||||||
|
const void *buffer = (const unsigned char *)_buffer + data->offset;
|
||||||
switch (data->vtype)
|
switch (data->vtype)
|
||||||
{
|
{
|
||||||
case Valve_Vector:
|
case Valve_Vector:
|
||||||
@ -239,9 +246,11 @@ DataStatus EncodeValveParam(IPluginContext *pContext,
|
|||||||
|
|
||||||
DataStatus DecodeValveParam(IPluginContext *pContext,
|
DataStatus DecodeValveParam(IPluginContext *pContext,
|
||||||
cell_t param,
|
cell_t param,
|
||||||
|
const ValveCall *pCall,
|
||||||
const ValvePassInfo *data,
|
const ValvePassInfo *data,
|
||||||
void *buffer)
|
void *_buffer)
|
||||||
{
|
{
|
||||||
|
void *buffer = (unsigned char *)_buffer + data->offset;
|
||||||
switch (data->vtype)
|
switch (data->vtype)
|
||||||
{
|
{
|
||||||
case Valve_Vector:
|
case Valve_Vector:
|
||||||
@ -269,7 +278,7 @@ DataStatus DecodeValveParam(IPluginContext *pContext,
|
|||||||
return Data_Fail;
|
return Data_Fail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mem += sizeof(Vector *);
|
mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
|
||||||
*realPtr = (Vector *)mem;
|
*realPtr = (Vector *)mem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,7 +325,7 @@ DataStatus DecodeValveParam(IPluginContext *pContext,
|
|||||||
return Data_Okay;
|
return Data_Okay;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mem += sizeof(QAngle *);
|
mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
|
||||||
*realPtr = (QAngle *)mem;
|
*realPtr = (QAngle *)mem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,8 +60,11 @@ struct ValvePassInfo
|
|||||||
PassType type; /**< IN: Pass information */
|
PassType type; /**< IN: Pass information */
|
||||||
unsigned int flags; /**< IN: Pass flags */
|
unsigned int flags; /**< IN: Pass flags */
|
||||||
size_t offset; /**< OUT: stack offset */
|
size_t offset; /**< OUT: stack offset */
|
||||||
|
size_t obj_offset; /**< OUT: object offset at end of the stack */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ValveCall;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts a valve parameter to a bintools parameter.
|
* @brief Converts a valve parameter to a bintools parameter.
|
||||||
*
|
*
|
||||||
@ -75,7 +78,8 @@ struct ValvePassInfo
|
|||||||
size_t ValveParamToBinParam(ValveType type,
|
size_t ValveParamToBinParam(ValveType type,
|
||||||
PassType pass,
|
PassType pass,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
PassInfo *info);
|
PassInfo *info,
|
||||||
|
bool &needs_extra);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Decodes data from a plugin to native data.
|
* @brief Decodes data from a plugin to native data.
|
||||||
@ -90,6 +94,7 @@ size_t ValveParamToBinParam(ValveType type,
|
|||||||
*/
|
*/
|
||||||
DataStatus DecodeValveParam(IPluginContext *pContext,
|
DataStatus DecodeValveParam(IPluginContext *pContext,
|
||||||
cell_t param,
|
cell_t param,
|
||||||
|
const ValveCall *pCall,
|
||||||
const ValvePassInfo *vdata,
|
const ValvePassInfo *vdata,
|
||||||
void *buffer);
|
void *buffer);
|
||||||
|
|
||||||
@ -106,6 +111,7 @@ DataStatus DecodeValveParam(IPluginContext *pContext,
|
|||||||
*/
|
*/
|
||||||
DataStatus EncodeValveParam(IPluginContext *pContext,
|
DataStatus EncodeValveParam(IPluginContext *pContext,
|
||||||
cell_t param,
|
cell_t param,
|
||||||
|
const ValveCall *pCall,
|
||||||
const ValvePassInfo *vdata,
|
const ValvePassInfo *vdata,
|
||||||
const void *buffer);
|
const void *buffer);
|
||||||
|
|
||||||
|
@ -23,8 +23,9 @@ inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsign
|
|||||||
#define ENCODE_VALVE_PARAM(num, which, vnum) \
|
#define ENCODE_VALVE_PARAM(num, which, vnum) \
|
||||||
if (EncodeValveParam(pContext, \
|
if (EncodeValveParam(pContext, \
|
||||||
params[num], \
|
params[num], \
|
||||||
|
pCall, \
|
||||||
&pCall->which[vnum], \
|
&pCall->which[vnum], \
|
||||||
vptr + pCall->which[vnum].offset) \
|
vptr) \
|
||||||
== Data_Fail) \
|
== Data_Fail) \
|
||||||
{ \
|
{ \
|
||||||
return 0; \
|
return 0; \
|
||||||
@ -33,8 +34,9 @@ inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsign
|
|||||||
#define DECODE_VALVE_PARAM(num, which, vnum) \
|
#define DECODE_VALVE_PARAM(num, which, vnum) \
|
||||||
if (DecodeValveParam(pContext, \
|
if (DecodeValveParam(pContext, \
|
||||||
params[num], \
|
params[num], \
|
||||||
|
pCall, \
|
||||||
&pCall->which[vnum], \
|
&pCall->which[vnum], \
|
||||||
vptr + pCall->which[vnum].offset) \
|
vptr) \
|
||||||
== Data_Fail) \
|
== Data_Fail) \
|
||||||
{ \
|
{ \
|
||||||
return 0; \
|
return 0; \
|
||||||
|
Loading…
Reference in New Issue
Block a user