STRPTR returning zero
Re: STRPTR returning zero
To the OP, why are you using strptr anyway?
-
- Posts: 1186
- Joined: May 08, 2006 21:58
- Location: Crewe, England
Re: STRPTR returning zero
Scanning text, in this case trying to separate an apartment number from the name of the block. Define a union of zstring ptr and ubyte ptr, then use the ubyte ptr to check for a string of numerics - asc("0") thru asc("9"). It's quicker than using string compare functions.caseih wrote:To the OP, why are you using strptr anyway?
Re: STRPTR returning zero
Since FB automatically casts a dynamic string to a zstring ptr on demand, you could do something like this and avoid explicit strptr calls:
And actually any time you're dealing with zstring ptrs, whether from strptr or not, checking for NULL is always a good idea, though I think that FB's strings should never have null pointers. An empty string should return a pointer to a real memory location that contains a NULL end of line character. Just to make the automatic conversion between strings and zstrings more complete.
Code: Select all
sub process_line(l as zstring ptr)
dim l as integer
if l <> 0 then 'check for NULL since empty dynamic strings have NULL pointers
slen = len(l)
'do something with it
end if
end sub
dim x as string
x = "Some line to parse"
process_line(x)
x = ""
process_line(x)
Wow that's very complicated. Are you sure this is the best way to do this? Have you profiled the execution of your program to determine that this particular string processing is the bottleneck? I suspect it's not. If your program is I/O bound than spending a few extra cycles to use FB's built-in string handling is not going to cost you anything. To me the simplest solution is going to be the better solution and less error prone.jevans4949 wrote:Scanning text, in this case trying to separate an apartment number from the name of the block. Define a union of zstring ptr and ubyte ptr, then use the ubyte ptr to check for a string of numerics - asc("0") thru asc("9"). It's quicker than using string compare functions.
Re: STRPTR returning zero
Yet everything seems to be fine:
But except for that:
Code: Select all
Dim As String s = ""
Print "'" & *Strptr(s) & "'"
Print Len(*Strptr(s))
Print Sizeof(*Strptr(s))
Dim As Zstring * 10 z = "FreeBASIC"
Print "'" & z & "'"
z = *Strptr(s)
Print "'" & z & "'"
Sleep
Code: Select all
''
0
1
'FreeBASIC'
''
Code: Select all
Print (*Strptr(s))[0]
Re: STRPTR returning zero
Hmm, interesting. It does appear to work with FB's built-in string handling, but when you hand off these empty strings to external, C-based routines, it's going to blow up. This is a bug in my opinion.
Here's an interesting program that shows this conflicting behavior:
Why does the first print statement even work? We know strptr(a) returns NULL, yet somehow we can dereference it and print it? In my opinion, the fact that the first print statement works at all is itself a bug. It should fail, given that the pointer really is 0. Also the len(*strptr("")) should also fail with a segfault.
Looking at the compiler output, it seems what is happening is that the runtime has print and len functions specifically for zstring ptrs and when you do something like len(*strptr("")), the dereference is actually removed by the compiler and it turns it into something more like this: fb_StrLen(strptr("")), and there's internal logic in that runtime function that just returns 0 if the length is zero. So this explains why the print statement worked, and why len works on the null pointers. To me this is questionable behavior as it hides NULL pointer problems. This is clearly a bug in FB, but I'm not sure the best fix for it. The entire problem could be avoided by always making sure strings, even empty strings have some memory associated with them, and have a intrinsic null character. Then a NULL pointer reference to print or len could result in a runtime error, which would be more in line with expected behavior.
Here's an interesting program that shows this conflicting behavior:
Code: Select all
#include "crt.bi"
dim as string a
a="hello"
a=""
print strptr(a)
print "'" & *(strptr(a)) & "'"
sub test(b as zstring ptr)
print *b 'probably okay but it won't actually print out for me
printf(!"%s\n",b) 'this obviously segfaults
end sub
print "---"
test (a)
Looking at the compiler output, it seems what is happening is that the runtime has print and len functions specifically for zstring ptrs and when you do something like len(*strptr("")), the dereference is actually removed by the compiler and it turns it into something more like this: fb_StrLen(strptr("")), and there's internal logic in that runtime function that just returns 0 if the length is zero. So this explains why the print statement worked, and why len works on the null pointers. To me this is questionable behavior as it hides NULL pointer problems. This is clearly a bug in FB, but I'm not sure the best fix for it. The entire problem could be avoided by always making sure strings, even empty strings have some memory associated with them, and have a intrinsic null character. Then a NULL pointer reference to print or len could result in a runtime error, which would be more in line with expected behavior.
Re: STRPTR returning zero
More generally concerning a dereferenced null Zstring Ptr
It seems that compiled code considers (except one case) a dereferenced null Zstring Ptr as an empty Zstring:
If that behavior is wanted? If yes, why not!
But when compiling such code with '-exx' option, it would be better in my opinion to have an error at runtime.
dkl, what is your opinion?
It seems that compiled code considers (except one case) a dereferenced null Zstring Ptr as an empty Zstring:
- Dim As Zstring Ptr
Dim As Zstring * 1 z- (*pz) is considered as (z).
- (*pz)[0]
Code: Select all
Dim As Zstring Ptr pz
Print "'" & *pz & "'"
Print Len(*pz)
Print Sizeof(*pz)
Dim As Zstring * 10 z = "FreeBASIC"
Print "'" & z & "'"
z = *pz & z
Print "'" & z & "'"
z = *pz
Print "'" & z & "'"
*pz = "a"
Print "'" & *pz & "'"
'Print (*pz)[0] '' aborting only when indexing a dereferenced null zstring ptr
Sleep
Code: Select all
''
0
1
'FreeBASIC'
'FreeBASIC'
''
''
But when compiling such code with '-exx' option, it would be better in my opinion to have an error at runtime.
dkl, what is your opinion?
-
- Posts: 2958
- Joined: Jun 02, 2015 16:24
Re: STRPTR returning zero
My feeling is that it make the code using such a mechanism still meaningful, and above all the program less prone to crash. This is like additional security, based on the fact that this is not stupid to considere null zstring ptr as an empty string.fxm wrote: It seems that compiled code considers (except one case) a dereferenced null Zstring Ptr as an empty Zstring
Re: STRPTR returning zero
I think treating a NULL zstring ptr as a zero-length string by FB's runtime is a very bad idea. The main reason is that the moment you hand off an empty dynamic string to a function defined in an external library, it's going to crash and the programmer isn't going to know why. There are very valid reasons for having empty strings and passing them to functions. And code like this is just obviously wrong, but FB silently allows it:
The above code works, contrary to all expectations of how pointers work. In my opinion, this kind of dereferencing should blow the program up with a runtime error. It certainly will blow things up the moment you try to use an external library with it.
But more critically, and this goes back to the OP's original problem, FB's handling of zero-length dynamic strings is broken. An empty string should have real memory associated to it with a null terminator byte for easy casting to zstring ptr when dealing with external functions. Seems to me this idea of letting the memory go when assigning an empty string is an optimization that was never really necessary. I haven't had time to go into the runtime library, but I would like to alter it and make a patch to get rid of this bad behavior. Should I file a bug report in the tracker?
Code: Select all
dim b as zstring ptr
b = 0
print *b
But more critically, and this goes back to the OP's original problem, FB's handling of zero-length dynamic strings is broken. An empty string should have real memory associated to it with a null terminator byte for easy casting to zstring ptr when dealing with external functions. Seems to me this idea of letting the memory go when assigning an empty string is an optimization that was never really necessary. I haven't had time to go into the runtime library, but I would like to alter it and make a patch to get rid of this bad behavior. Should I file a bug report in the tracker?
Re: STRPTR returning zero
But this isn't additional security. This is actually making things much worse by hiding the NULL pointer problem. Far better to crash with a runtime error so you know what the problem actually is, rather than going for weeks, months, or years with hidden modes of failure in your program. Especially if the source of the pointer is from somewhere other than FB's dynamic string descriptor.Tourist Trap wrote:My feeling is that it make the code using such a mechanism still meaningful, and above all the program less prone to crash. This is like additional security, based on the fact that this is not stupid to considere null zstring ptr as an empty string.
Re: STRPTR returning zero
For my part I would wish at least the runtime error code 7 (Null Pointer Access) on any dereferencing of null zstring pointer when one compiles with the '-exx' option.
-
- Posts: 2958
- Joined: Jun 02, 2015 16:24
Re: STRPTR returning zero
Yes that would be elegant from -exx switch to give this info.fxm wrote:For my part I would wish at least the runtime error code 7 (Null Pointer Access) on any dereferencing of null zstring pointer when one compiles with the '-exx' option.
I would agree with you, but maybe a null zstring ptr can be considered as equivalent of the null string. I don't know, but it seems that zstring only occures in the context of strings, so it may not be like for the pointers in general, where null means absolutely nothing clear.caseih wrote:This is actually making things much worse by hiding the NULL pointer problem.
Re: STRPTR returning zero
I don't really see a problem, maybe a small inconsistency at best...
Printing *myStringPtr or *myZstringPtr will call the Print function and pass the string Byref, and as it happens, it checks for NULL, and prints nothing in that case. That's a pretty good way of dealing with that problem, don't you think? Alternatively it could crash, or print something like "(null)" like some CRTs' printf() does. But that seems worse to me than printing nothing.
And consider this:
You can pass a NULL reference, and it won't crash or be caught by -exx until accessed.
Or another, related case:
That's how offsetof() is implemented, should -exx catch that too? There's a NULL pointer dereference in the source code, but not in the final program. Maybe that's the main inconsistency issue here?
Printing *myStringPtr or *myZstringPtr will call the Print function and pass the string Byref, and as it happens, it checks for NULL, and prints nothing in that case. That's a pretty good way of dealing with that problem, don't you think? Alternatively it could crash, or print something like "(null)" like some CRTs' printf() does. But that seems worse to me than printing nothing.
And consider this:
Code: Select all
sub f(byref i as integer)
end sub
dim pi as integer ptr = 0
f(*pi)
Or another, related case:
Code: Select all
type UDT
as integer a, b, c
end type
print @cptr(UDT ptr, 0)->c
Re: STRPTR returning zero
And for that, one special case?
Code: Select all
Dim As Integer Ptr pi = 0
Dim As Integer i= 1
'i = *pi '' runtime error 7 (null pointer access)
Dim As Zstring * 10 z = "FreeBASIC"
Dim As Zstring Ptr pz = 0
z = *pz '' ok
-
- Posts: 2958
- Joined: Jun 02, 2015 16:24
Re: STRPTR returning zero
As I understand *pz return the null string if pz=0.fxm wrote:Code: Select all
z = *pz '' ok
In the case of an integer, I don't know why but it wouldn't make sense for me, but for strings it seems ok. But I suppose that a null pointer could in the absolute be dereferenced with a conventional value (default or other).
Re: STRPTR returning zero
That seems normal that the runtime check (requested by '-exx') to test the null pointers works only for the variables and not for the constants or literals (at worst these last could being processed at compile time).dkl wrote:That's how offsetof() is implemented, should -exx catch that too? There's a NULL pointer dereference in the source code, but not in the final program. Maybe that's the main inconsistency issue here?Code: Select all
type UDT as integer a, b, c end type print @cptr(UDT ptr, 0)->c