ID:2525611
 
Resolved
replacetext() did not work correctly when replacing a blank string, sometimes resulting in crashes.
BYOND Version:513.1501
Operating System:Linux
Web Browser:Firefox 70.0
Applies to:Dream Daemon
Status: Resolved (513.1502)

This issue has been resolved.
Descriptive Problem Summary:
replacetext returns odd results or crashes when passed odd, but valid arguments

Numbered Steps to Reproduce Problem:
- Try replacetext("a", md5("1"), "b") and receive either '1' or the name of the proc you ran it in
- Try replacetext("a", "", "b") and receive BUG output

Code Snippet (if applicable) to Reproduce Problem:
#define DEBUG

/world/New()
testA()
testB()
testC()

/proc/testA()
var/a = replacetext("a", md5("1"), "b")
world.log << "a: '[a]'"

/proc/testB()
var/b = replacetext("a", md5("12"), "b")
world.log << "b: '[b]'"

/proc/testC()
var/c = replacetext("a", "", "b")
world.log << "c: '[c]'"


Expected Results: The same output as in 512.1488:
a: 'a'
b: 'a'
c: 'ba'


Actual Results:
a: '/proc/testA' // this is sometimes '1', but I'm not sure why or how to reproduce this
b: '/proc/testB'
BUG: Crashing due to an illegal operation!
proc name: testC (/proc/testC)
source file: test.dme,17
usr: (src)
src: null
call stack:
testC()
world: New()

Backtrace for BYOND 513.1501 on Linux:
Generated at Wed Nov 27 20:37:37 2019

DreamDaemon [0x8048000, 0x0], [0x8048000, 0x804bd94]
libc.so.6 [0xf71e5000, 0x0], 0x14dd46
linux-gate.so.1 [0xf7f18000, 0xf7f18950], [0xf7f18000, 0xf7f18950]
libc.so.6 [0xf71e5000, 0x0], 0x14dd46
libbyond.so 0x39fd50, 0x39fda6
libbyond.so [0xf7915000, 0x0], 0x2d13ce
libbyond.so [0xf7915000, 0x0], 0x2c5e67
libbyond.so [0xf7915000, 0x0], 0x2cfa12
libbyond.so [0xf7915000, 0x0], 0x2adf7e
libbyond.so [0xf7915000, 0x0], 0x2cd984
libbyond.so [0xf7915000, 0x0], 0x2da523
libbyond.so [0xf7915000, 0x0], 0x2da82b
libbyond.so [0xf7915000, 0x0], 0x2818d6
libbyond.so [0xf7915000, 0x0], 0x2840eb
libbyond.so [0xf7915000, 0x0], 0x27ebd1
libbyond.so [0xf7915000, 0x0], 0x27f63e
libbyond.so 0x302f90, 0x302fd7
DreamDaemon [0x8048000, 0x0], [0x8048000, 0x804aeff]
libc.so.6 0x1eeb0, 0x1efa9 (__libc_start_main)
DreamDaemon [0x8048000, 0x0], [0x8048000, 0x804a801]

Recent proc calls:
/proc/testC
/proc/testB
/proc/testA
/world/New



Does the problem occur:
Every time? Or how often? Every time
In other games? Yes
In other user accounts? Yes
On other computers? Yes

When does the problem NOT occur? When either md5() is not used, or the "find" argument to replacetext() is not empty.

Did the problem NOT occur in any earlier versions? If so, what was the last version that worked?
Works fully in 512.1488.
testA and testB don't work starting in 513.1490, but testC does.
testC first breaks in 513.1493.

Workarounds: Don't do this?
md5() itself seems to be causing things to break when used inline. Our expression bot (running 1497) just completely fails to print anything sent to world.log on the same line as a call to md5(), but will work just fine if it's assigned to a variable first.
...wait, what.

[27 21 47 58] [GinjaNinja32] !dm world.log << md5("foo");;
[27 21 48 00] [testbot] <no output>


but the typo I made in my initial attempt probably shows the bug better:
[27 21 47 47] [GinjaNinja32] !dm world.log << md5("foo")
[27 21 47 49] [testbot] runtime error: type mismatch: "/proc/main" << "acbd18db4cc2f85cedef654fccc4a4..."; proc name: main (/proc/main); usr: (src); src: null; call stack:; main(); world: New();


That'd explain why the replacetext() is coming back with the name of the proc it's in unexpectedly - because md5() is breaking the value that precedes it (?) to be that proc name.
It seems that it replaces the previous value with the arg passed to md5() if said arg is already in the string tree, and the name of the current proc otherwise. Or something.
That would explain my comment in the initial post that replacetext("a", md5("1"), "b") was sometimes "1" but I couldn't reproduce it - I only ever saw that in my bot's DM evaluation environment, which includes a file of utility functions, one of which contains the string literal "1"; if I try replacetext("a", md5("F"), "b"), I get "F", but replacetext("a", md5("G"), "b") is "/proc/main", the proc name; the same function that contains "1" contains "F", but not "G".
Apparently I wasn't quite right, and it only replaces it with the arg if the arg is a string present at compile time, not simply present on the string tree. But I also discovered that it replaces it with nothing (?) if the arg isn't a constant, and replaces it with the proc name again if it's a const var but only if the const's definition is the only compile-time occurrence of its value (???)

I kind of doubt any of this information is useful, but it sure is interesting
Lummox JR resolved issue with message:
replacetext() did not work correctly when replacing a blank string, sometimes resulting in crashes.