Archive for February, 2015

.NET fejtörő 6. – megoldás

Friday, February 27th, 2015

Feladat.

Nincs mit írnom a megoldásról, Varga Tamás kolléga (ezek köszönet érte) annyira részletesen, alaposan kielemezte a témát a kommentek között, hogy ennél én csak kevesebbet tudnék írni, övé a szó, olvassátok.

TDD akció újra

Friday, February 27th, 2015

Tavaly már volt egy ilyen akcióm, az megtöltötte a termet (150k < 200k). Gyere, ne maradj le róla.

.NET fejtörő 5. – megoldás

Sunday, February 22nd, 2015

A fejtörő.

Molnár Csaba olyan teljesen megválaszolta a kérdést (köszönet érte), hogy a kommentjét egy az egyben bepasztázom:

C#-ban az idexer egy indexelt property, aminek alapértelmezetten Item a neve. Ezért fordítási hibát kapunk ennél a kódnál, hogy már van definíció az Item-re.
Ezt kétféle módon tudjuk elkerülni:
1. Az Item property-t átnevezzük valami másra.
2. Használjuk az indexeren az IndexerNameAttribute-ot, amivel megadhatjuk, hogy milyen néven jöjjön létre az indexer (ne Item néven).

Én személy szerint nem erőltetném a névütközést, inkább választanék más nevet.

Ami pluszként érdekes a példában (nekem nem volt magától értetődő), hogy lehet használni a params módosítót indexer esetén is.

SQL fejtörő 7. – megoldás

Sunday, February 22nd, 2015

Kérdés: meg tudom-e nézni egy hosszan futó SQL DML lekérdezésnél, hogy a mögötte futó operátorok (join, index seek, stb.) hány százaléknál járnak?

SQL Server 2014-től igen!

Nézzük a következő (buta) lekérdezést:

SET STATISTICS PROFILE ON;
GO
--Next, run your query in this session
select * from [dbo].[Nums] n1 cross join dbo.Nums n2;

Ez egy lassú, sok soros cross join, csak demó célra. A vizsgálandó lekérdezést olyan sessionben kell futtatni, amiben a STATISTICS PROFILE be van kapcsolva.

Így néz ki a végrehajtási terve:

CrossJoinPlan

A terv fontos a következőkhöz, azért raktam ide. És most jön a lényeg: sys.dm_exec_query_profiles. Ő mutatja meg, belül mi zajlik:

SELECT  
   node_id,physical_operator_name, SUM(row_count) row_count, SUM(estimate_row_count) AS estimate_row_count, 
   CAST(SUM(row_count)*100 AS float) / SUM(estimate_row_count) PercentComplete
FROM sys.dm_exec_query_profiles 
--WHERE session_id=54
GROUP BY node_id,physical_operator_name
ORDER BY node_id;

A végrehajtás kezdetén így néz ki a kimenete (ha valaki tud tippet adni, hogy lehet ezt SyntaxHighlighterrel jól formázni megköszönöm):

node_id	physical_operator_name	row_count	estimate_row_count	PercentComplete
0	Parallelism		1320422		4294967295		0.030743470422631
1	Nested Loops		1323284		4294967296		0.0308101065456867
2	Clustered Index Scan	15		100000			0.015
3	Table Spool		1323284		1410065408		0.0938455757082157
4	Clustered Index Scan	400000		400000			100

Egy perccel később:

node_id	physical_operator_name	row_count	estimate_row_count	PercentComplete
0	Parallelism	15917761	4294967295	0.370614254002137
1	Nested Loops	15920504	4294967296	0.370678119361401
2	Clustered Index Scan	161	100000	0.161
3	Table Spool	15920504	1410065408	1.12906138322911
4	Clustered Index Scan	400000	400000	100

Mit jelen ez? A terv alapján van két clustered index scanünk. Az egyik felolvasta a táblában található 400000 sort, azzal ő végzett is. Aztán a cilusos join elkezdi hozzávenni a tábla sorait, minden sorhoz 400000-et. Az egész eredménye belekerül a Table Spoolba, majd csurog ki a Parallelism operátoron keresztül (ami Gather Stream műveletet hajt végre, azaz összegyűjti a több szál által összerakott sorokat egy streambe, mivel párhuzamos a terv).

Lássuk be, marha érdekes látni, hogy áll belül egy nagyobb DML művelet, nem?

.NET fejtörő 4. – megoldás

Saturday, February 14th, 2015

Kérdés: miért nem jó, ha az ASP.NET Machine Key-emet Random.NextBytes()-szal generálom?

A Machine Key-t alapban viewstate validálásra használja az ASP.NET. HMAC algoritmussal csinál egy hasht, amihez a Machine Key-t mint kulcsot is felhasználja. Ez a kevésbé problémás dolog. Ami sokkal veszettebb, hogy amikor beléptetünk valakit az ASP.NET forms security-vel, akkor a beléptetett felhasználót azonosító adatot ezzel a Machine Key-jel titkosítják. Ha valaki megismeri ezt a kulcsot, akkor tud generálni kamu kukit, amibe azt a user id-t ír be, amit csak akar. Azaz meg tud személyesíteni másokat. Ebből aztán lesz spoofing, vagy akár elevation of privilege. Magyarul senki nem szeretné, ha bárki más beléphetne a nevében egy védett website-on. Például az internetes bankjába.

Szóval, talán most már érthető, a Machine Key-t nem szeretnénk, ha bárki megszerezné vagy kitalálná. Megszerezni csak a site feltörésével lehet, és admin jogokkal, tegyük fel ez nem történt meg. Ha azonban a véletlen sorozat generátorunk kiszámítható, akkor más is ugyanazzal az algoritmussal tud generálni egy olyan kulcsot, amit én is generáltam. És már jönnek is be más nevében.

A .NET Random pszeudo-random generátor, azonos seed-del mindig ugyanaz a sorozat jön ki belőle. Azt mondjátok de én ravasz vagyok, és beadom a DateTime.Now.Ticket neki inputként, az úgysem tudja a támadó. Nem tudja, de pörgetni ő is tudja ezt a számot addig, amíg ki nem találja a megfelelő seedet.

Mi a megoldás? Olyan random generátor kell, ami teljesen kiszámíthatatlan. Pl. a termikus zaj digitalizálva tökéletesen jó erre a célra. Ha ilyen modul nincs a gépben, akkor a Windows megpróbál valami nagyon randommal kijönni, például összerakva olyan vad perf counter értékeket, mint a proci ventilátor sebessége és egyebek.

A lényeg, hogy ha cripto szinten random érték kell, akkor az RNGCryptoServiceProvider típust kell használni erre a célra.

Egyébként meg IIS 7.5-től machine key-t tud generálni az IIS Manager GUI is. :)

SQL fejtörő 9.

Friday, February 13th, 2015

Van egy táblánk, amiben számokat tárolunk. A számok nem teljesen folytonosak, az összefüggő részeket kell azonosítani.

use tempdb;

IF OBJECT_ID('dbo.Tabla', 'U') IS NOT NULL DROP TABLE dbo.Tabla;
GO
CREATE TABLE dbo.Tabla
(
	szam INT NOT NULL CONSTRAINT PK_Tabla PRIMARY KEY
);
INSERT INTO dbo.Tabla(szam)
VALUES(12),(13),(111),(112),(113),(237),(238),(340),(350),(351);
GO

select * from Tabla;

-- Ezt szeretnénk kinyerni, az összefüggő tartományokat
--tartomanyeleje	tartomanyvege
--12				13
--111				113
--237				238
--340				340
--350				351

A megfejtéseket szokás szerint kommentben várom, amelyeket 2 nap múlva engedek ki.

.NET fejtörő 6.

Wednesday, February 11th, 2015

Miért fogják feltörni könnyen az alábbi jelszó ellenőrzőt? Ne csak a nyilvánvaló okokat írjátok meg.

private static bool PassValidator(string pass)
{
    string passInDb = "password";   //az eredeti implementációban valahonnan memória cacheből jön az adat

    int i;
    for (i = 0; i < pass.Length; i++)
    {
        if (pass[i] != passInDb[i])
        {
            break;
        }
    }
    return i == passInDb.Length;
}

.NET fejtörő 3. – megoldás

Tuesday, February 10th, 2015

Íme a kiírás.

Álljon itt újra a kód is:

struct Counter
{
    int counter;
    public override string ToString()
    {
        return counter++.ToString(CultureInfo.InvariantCulture);
    }
}

[TestMethod]
public void Teaser3()
{
    var sb = new StringBuilder();
            
    var sz = new Counter();
            
    sb.Append(sz);
    Object p = sz;
    Object o = p;
    sb.Append(sz);
    sb.Append(o);
    sb.Append(p);
    sb.Append(o);

    Assert.AreEqual("01234", sb.ToString());
}

Először lemaradt a feladatból a Counter struktúra, anélkül nem volt sok értelme a feladatnak, ezért az első pár választ nyilván félre mehetett.
A feladatban az a trükk, hogy nem class, hanem struktúra a Counter típus. A StringBuilderben a végén 00012 lesz. Miért?

Az sz egy a veremben tárolt struktúra. Az sb.Append() (ebben az esetben) objektumot vár paraméterül (ami reference type), amin meghívja a ToString() metódust, és ennek kimenetét rakja bele az építendő stringbe. Azonban az sz egy struktúra, value type, így azt a CLR-nek fel kell másolnia a heapre. Ezt hívják boxingnak. Ezen pont után a ToString() már a másolaton hívódik meg, az eredeti sz counter mezeje érintetlen marad.
Mivel postfix ++ operátort használunk, a kifejezés kimenete a növelés előtti érték lesz, azaz 0. Ez az első számunk.
Az Object p = sz explicit felboxolja sz-t a heapre. Az Object o = p pusztán egy másik referencia lesz ugyanerre az értékre.
Ezek után sb.Append(sz) újra boxol és kiírja a 0-t, mint a korábbi esetben. Ez a 2. számunk. Sokan szerintem itt már 1-et vártak, ami így is lenne, ha a Counter classként lenne definiálva.
Az sb.Append(o) az eddig még érintetlen felboxolt példányon hívódik meg. Mivel megint csak postfix ++ van, ez is 0 lesz. Ez a 3. 0.
Az sb.Append(p) ugyanezen példányra mutat, így végre ő már megnövelheti a számlálót 2-re, és visszaadhatja az 1-et. Ez a 4. számunk, ami végre 1.
Az sb.Append(o) pedig újra végigjátssza a növelést a más ismerős példánnyal, így jön ki belőle 2.

Ha a típusunk class lett volna, akkor jött volna ki belőle 01234.

A példának látszólag nincs jelentősége, a generikus típusok óta valóban kevesebb baj van a struktúrákkal. De még .NET 1.0-ban láttam olyat, amikor HashTable[“valami”]++ után a x = HashTable[“valami”] változatlan értéket adott vissza, meglepve a kollégákat. Most már talán érthető, miért.

SQL fejtörő 8.

Tuesday, February 10th, 2015

SQL Serveren dolgozva van egy agresszív lekérdezés, amely szétzúzza a diszket, így a többi lekérdezés nem kap elég időt, kiéhezteti őket. Mit tudok tenni?

.NET fejtörő 5.

Monday, February 9th, 2015

Mi a gond az alábbi kóddal?

class Teaser4
{
    int Item = 0;

    public int this[params int[] arr]
    {
        get
        {
            return Item;
        }
    }
}

.NET fejtörő 3. hiánypótlás

Friday, February 6th, 2015

Elnézést azoktól, akik filóztak a 3. .NET feladaton, elfelejtettem belerakni a Counter típust, anélkül semmi értelme a feladatnak. Így már érthető, miért nem jött rá megoldás. :)

Most akkor neki lehet esni még egyszer.

SQL fejtörő 7.

Friday, February 6th, 2015

Meg tudom-e nézni egy hosszan futó SQL DML lekérdezésnél, hogy a mögötte futó operátorok (join, index seek, stb.) hány százaléknál járnak?

.NET fejtörő 4.

Thursday, February 5th, 2015

Ez most egy elméleti kérdés lesz. Van egy web farmom. Az ASP.NET Machine Key-emet legeneráltam a Random.NextBytes() segítségével, és beraktam minden gép machine.configjába. Mi a probléma a megoldásommal?

.NET fejtörő 3 – nincs megoldás?

Thursday, February 5th, 2015

Itt volt ez a fejtörő, de nem jött rá megoldás. Ennyire nem nehéz. Valaki?

.NET fejtörő 2. megoldás

Thursday, February 5th, 2015

Feladat itt.

Emlékeztetőűl a feladat:

var sb = new StringBuilder();

for (int i = 0; i < 10; i++)
{
    sb.Append(i + ' ');
}

A művelet kimenete:
32333435363738394041

Miért?

i integer, ‘ ‘ char. A char nem más, mint egy 16-bites numeric (ordinal) érték, mi implicit konvertálható más, nagyobb vagy azonos méretű egészekké.
Azaz a ‘ ‘ szóköz karakter 32-es kódját kell hozzáadni a ciklusváltozóhoz, ezért jön ki egy számsorozat végeredményként.