6

As .NET doesn't use C style nulls to end a string how can I keep the allocated string but change the length of it by using unsafe code?

As I understand .NET using a 20 bytes header for every string, presumably this is where the length of the string is stored, is there anyway to directly modify this length? So .NET will keep the string in memory but when I call .Length it'll return the .Length I want.

if this is possible, also it would be interesting to hear all crazy possible side-effects of this

UPDATE

I'm trying accomplish this without using reflection.

dr. evil
  • 26,944
  • 33
  • 131
  • 201
  • 2
    Note that .Net strings are null-terminated. – SLaks Nov 18 '11 at 01:08
  • 1
    What do you need to do THAT for? – Jacob Nov 18 '11 at 01:08
  • @jacob some evil experiment about memory management :) Trying allocate one large chunk of memory and reuse it constantly without to avoid LOH fragmentation. – dr. evil Nov 18 '11 at 01:13
  • @SLaks I know but adding a null byte to middle of a string will not change how it's treated as null character .NET strings is treated as any other character. – dr. evil Nov 18 '11 at 01:15

2 Answers2

6

From Strings UNDOCUMENTED

public static unsafe void SetLength(string s, int length)
{
    fixed(char *p = s)
    {
        int *pi = (int *)p;
        if (length<0 || length > pi[-2])
            throw( new ArgumentOutOfRangeException("length") );
        pi[-1] = length;
        p[length] = '\0';
    }
}
Chris Fulstow
  • 41,170
  • 10
  • 86
  • 110
  • 2
    Note that the string class has changed substantially in .Net 4; it now only has two fields. – SLaks Nov 18 '11 at 01:14
  • Wow, exactly what I was looking for, I'll test this now – dr. evil Nov 18 '11 at 01:16
  • Is there any article around for .NET 4.0 updates related to `System.String` updates? – dr. evil Nov 18 '11 at 01:17
  • Works perfectly as expected, now I wonder what awkward problems I'm going to have :) – dr. evil Nov 18 '11 at 01:23
  • @dr. evil I'm sure there will be a painful "it doesn't work" session for some poor replacement in the future when you're long gone as soon as .NET xyz rolls-around or it's used on an alternate run-time (Mono?) or a non-x86/64 .NET or ... At least, hopefully it's a replacement and not you by that time ;-) –  Nov 18 '11 at 01:27
  • @pst Sure it'll fail in some places but just for the records it works in .NET 4.0 and x64 – dr. evil Nov 18 '11 at 01:29
  • @dr. evil Which is neat, but "how much does it really gain"? There are a number of approaches to this problem, I'm sure. This is sort of an ... evil one :) Poor interned string or strings used in a hash or ... YMMV for sure. –  Nov 18 '11 at 01:30
  • @pst unfortunately there isn't, pretty much only real solution to this problem is restarting your application. Please tell me if you know a solution to LOH Fragmentation, because seems like no one got a solution to it. The question is how can you allocate thousands of large strings without causing LOH Fragmentation? – dr. evil Nov 18 '11 at 01:55
  • @pst take a look at this question which is related with I'm trying to accomplish : http://stackoverflow.com/questions/8020550/regex-stringbuilder-and-large-object-heap-fragmentation – dr. evil Nov 18 '11 at 01:57
  • @dr.evil - I work on complex Windows client apps that juggle lots of data and can run for days. I haven't needed to hack .NET to get them to work. That said, since you have experienced issues, perhaps .NET is not the right platform for your needs. – TrueWill Nov 18 '11 at 02:59
  • @TrueWill Maybe it's maybe it's not, but guess what rewriting 10 year man day code in C++ is harder than hacking .NET to fix one problem. – dr. evil Nov 18 '11 at 03:04
  • Nice! This helped me save an extra memory copy on https://stackoverflow.com/a/37368176/2352507 (obviously this is "unsafe" but users should be reminded every time because of having to use the "unsafe" keyword) – SunsetQuest May 28 '21 at 15:30
0

You can use Reflection to set the m_StringLength field.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Sorry forgot to say I'm trying to this unsafe code directly and not with reflection, updated the question. – dr. evil Nov 18 '11 at 01:13