vvp: Handle null-bytes in the string literal VPI support
The VPI API for string literals does not correctly handle the case where a
null-byte ('\0') appears in the string literal. It uses strlen() to
calculate the length of the literal, which will give the wrong result if
there is a null-byte in the string literal. Instead of using strlen() use
the stored length to fix this.
In addition when formatting a string literal as a string ignore any
null-bytes. The LRM is not entirely clear what should happen to null-bytes
when formatting a value as a string. But the behavior of ignoring the
null-bytes is consistent with the rules of SystemVerilog for converting a
string literal to a SV string.
This problem can occur when a string literal gets null-byte left-padded due
to width of its context of its expression, but then optimization removes
part of the expression and only leaves the padded string literal.
E.g.
```
$display(0 ? "Yes" : "No");
```
will be transformed into
```
$display("\000No");
```
There is also one subtle change in behavior associated with this. The empty
string ("") is supposed to be equivalent to 8'h00. So e.g.
`$display(":%s:", "")` should print ": :" since the width of the empty
string is 1 byte and the %s modifier prints a string with the width of the
value, left-padding with spaces if necessary. The current implementation
will print "::" though. This change requires to update the marco_with_args
gold file.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
23e51ef7a8
commit
b8ddeb8848
|
|
@ -1,4 +1,4 @@
|
|||
first..last first,last last..first
|
||||
(a)..(c) (a,b,c) (c)..(a)
|
||||
(a )..(c ) (a,b,c) (c )..(a )
|
||||
sumsqr(3,4) = 25
|
||||
sumsqr(5,12) = 169
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ int __vpiStringConst::vpi_get(int code)
|
|||
{
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return strlen(value_)*8;
|
||||
return value_len_ * 8;
|
||||
|
||||
case vpiSigned:
|
||||
return 0;
|
||||
|
|
@ -121,7 +121,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp)
|
|||
{
|
||||
unsigned uint_value;
|
||||
p_vpi_vecval vecp;
|
||||
unsigned size = strlen(value_);
|
||||
unsigned size = value_len_;
|
||||
char*rbuf = 0;
|
||||
char*cp;
|
||||
|
||||
|
|
@ -131,9 +131,22 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp)
|
|||
vp->format = vpiStringVal;
|
||||
// fallthrough
|
||||
case vpiStringVal:
|
||||
cp = value_;
|
||||
rbuf = (char *) need_result_buf(size + 1, RBUF_VAL);
|
||||
strcpy(rbuf, value_);
|
||||
vp->value.str = rbuf;
|
||||
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
// Ignore leading null-bytes and replace other null-bytes with space.
|
||||
// The LRM is not entirely clear on how null bytes should be handled.
|
||||
// This is the implementation chosen for iverilog.
|
||||
if (*cp)
|
||||
*rbuf++ = *cp;
|
||||
else if (rbuf != vp->value.str)
|
||||
*rbuf++ = ' ';
|
||||
|
||||
cp++;
|
||||
}
|
||||
*rbuf = '\0';
|
||||
break;
|
||||
|
||||
case vpiDecStrVal:
|
||||
|
|
|
|||
Loading…
Reference in New Issue